《Python渗透测试编程技术:方法与实践》基础篇:工具安装~

一、更换源与安装工具everything(老版本叫all)

1、在sources.list 文件中更改

	//方法1:vim
	sudo vim /etc/apt/sources.list
	//方法2:nano
	//这个超级好用,都不需要更改sources权限,ctrl+S保存,ctrl
	sudo nano /etc/apt/sources.list

2、将下面的源复制粘贴进去
只用其中一个源就行,比如我用的阿里源,就把别的注释掉啦。如果需要用别的源,就用“#”注释掉阿里云源,要用的就不注释。

	#deb http://http.kali.org/kali kali-rolling main non-free contrib
	#deb-src http://http.kali.org/kali kali-rolling main non-free contrib
	#中科大源
	#deb http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib
	#deb-src http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib
	#阿里云源
	deb http://mirrors.aliyun.com/kali kali-rolling main non-free contrib
	deb-src http://mirrors.aliyun.com/kali kali-rolling main non-free contrib
	#清华大学源
	#deb http://mirrors.tuna.tsinghua.edu.cn/kali kali-rolling main contrib non-free
	#deb-src https://mirrors.tuna.tsinghua.edu.cn/kali kali-rolling main contrib non-free
	#浙大源
	#deb http://mirrors.zju.edu.cn/kali kali-rolling main contrib non-free
	#deb-src http://mirrors.zju.edu.cn/kali kali-rolling main contrib non-free

3、然后更新源并升级安装

	sudo apt-get update  # get更新的软件包列表信息
	sudo apt-get upgrade # 进行一次升级
	sudo apt-get clean # 删除已经下载的安装包
	sudo reboot  #重启

4、开始安装工具
安装 kali-linux-wireless

	sudo apt-get update && apt-cache search kali-linux-wireless
	sudo apt-get install kali-linux-wireless

失败: E:无法定位软件包kali-linux-wireless。然后去找别的解决办法~
后来还是没解决,但是搜到一篇博客说,新版里面all变成了everything,我就试了一下。果然在安装了,我就假装它是安装成功了所有工具吧。后面用的时候有啥问题再去找解决方案~

sudo apt-get install kali-linux-everything

5、vmtools灰了,与主机同步的复制粘贴失效

apt-get dist-upgrade
apt-get install open-vm-tools-desktop fuse3
apt-get install linux-headers-$(uname -r)
rebot

这样好像就可以有VMtools功能了,虽然我那个“重新安装VMtools的那一行按钮还是灰色的”,有功能可用就行,我选择不管它了

二、在kali上安装pycharm

1、先查看python版本
如果没有的话,需要自己装一下,但是我装的22.01版kali是有python3.9的。

	python --version

2、官网下载pycharm社区版并安装
因为社区版不收费啦~而且社区版的功能在入门学习阶段够用啦
下载pycharm官网
在这里插入图片描述
建议在主机下载,速度快些,下载之后在本地解压,然后拖进kali里面即可。在主目录新建kali/Downloads文件夹,把解压后的文件夹拷贝进这个新建文件夹下面。
通过命令打开pycharm。

sudo ln -s /home/kali/Downloads/pycharm-community-2022.1.1/bin/pycharm.sh /usr/bin/pycharm.sh
sudo pycharm
#打开pycharm用sudo,养成习惯,因为有很多程序需要root权限

3、设置pycharm项目保存位置
新建项目test,确定好位置名称和interpreter之后,就点create创建。
在这里插入图片描述
4、第一个py程序
在test项目下右键新建一个test.py文件,写入代码
然后点左边绿色左三角运行,或者右键->Run‘test’。就会显示结果啦

	print("hello ~test01!")

在这里插入图片描述

(1)后来遇到一个问题,就是把interpreter搞不见了。然后需要把它调回来。左上角File->Settings->Project:test点开->Project interpreter->选择python版本,然后点ok就行。有可能在没有interpreter的时候点进去有好几个可以选的地方,选中system那个,然后按照下图类似的操作即可。
在这里插入图片描述
在这里插入图片描述
(2)后来我每次打开pycharm都要更新索引很久很久,好烦,但是就那样吧。以防万一,小白如我,先跟着书上搞,之后再换成VSCode。

四、网络渗透测试常见模块

1、Soket模块文件
(1)socket介绍
Socket不是TCP/IP协议族里面的协议,而是一个编程接口。python里面有两个与其模块: 第一个是 Socket,它提供了标准的 BSD Sockets API。第二个是 SocketServer, 它提供了服务器中心类,可以简化网络服务器的开发。
(2)socket对象方法

s.bind(address) #将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址。

sk.listen(backlog)#开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。backlog等于5,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的连接个数最大为5。 这个值不能无限大,因为要在内核中维护连接队列

sk.setblocking(bool)# 是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。

sk.accept()#接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。接收TCP 客户的连接(阻塞式)等待连接的到来

sk.connect(address)# 连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。

sk.connect_ex(address) #同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码,例如:10061

sk.close() # 关闭套接字

sk.recv(bufsize[,flag]) # 接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。

sk.recvfrom(bufsize[.flag]) # 与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。

sk.send(string[,flag]) # 将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送。

sk.sendall(string[,flag])  # 将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。内部通过递归调用send,将所有内容发送出去。

sk.sendto(string[,flag],address)  #  将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。

sk.settimeout(timeout) # 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s )

sk.getpeername() #  返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。

sk.getsockname()  #  返回套接字自己的地址。通常是一个元组(ipaddr,port)

sk.fileno()  # 套接字的文件描述符
(2)经典小例子
编写一个简单的可以互相通信的服务器端和客户端程序。
服务器端——server.py
import socket
s1 = socket.socket()
s1.bind(("127.0.0.1",2345))
s1.listen(5)
str ="hello socket20220531"
while 1:
conn,address = s1.accepto
print("a new connect from " , address)
conn.send(str.encode())
conn.close()

客户端——client.py

import socket
s2 = socket.socketo)
s2.connect(("127.0.0. 1"2345))
data = bytes.decode(s2.recv (1024))s2.close(
print(data)

(3)运行图片
感觉很神奇诶,每多点击一次客户端运行,服务器端打印的客户端地址就会发生改变,且在我电脑上是每次递增2。【问题20220601,等之后会了再回来解答这个问题~】
在这里插入图片描述
在这里插入图片描述

2、python-nmap模块
简介:python-nmap模块中的核心是PortScanner、PortScannerAsync、PortScannerError、PortScannerHostDict、PortScannerYield这5个类,其中最重要的是PortScanner类。
-----------------------PortScanner类-----------------------

scan() #这个函数的完整形式为:
scan(self, hosts='127.0.0.1', ports=None, arguments='-sV',sudo=False)
#用来对指定目标进行扫描,其中需要设置的三个参数包括hosts、ports和arguments。
#hosts的值为字符串类型,表示要扫描的主机,形式可以是IP地址,例如“192.168.1.1”,也可以是一个域名,例如“www.nmap.org”。
#ports的值也是字符串类型,表示要扫描的端口。如果要扫描的是单一端口,形式可以为“80”。
#如果要扫描的是多个端口,可以用逗号分隔开,形式为“80,443,8080”。如果要扫描的是连续的端口范围,可以用横线,形式为“1-1000”。
#arguments的值也是字符串类型,这个参数实际上就是Nmap扫描时所使用的参数,
#如“-sP”“-PR”“-sS”“-sT”“-O”“-sV”等。
#“-sP”表示对目标进行Ping主机在线扫描,
#“-PR”表示对目标进行一个ARP的主机在线扫描,
#“-sS”表示对目标进行一个TCP半开(SYN)类型的端口扫描,
#“-sT”表示对目标进行一个TCP全开类型的端口扫描,
#“-O”表示扫描目标的操作系统类型,
#“-sV”表示扫描目标上所安装网络服务软件的版本。
#如果要对192.168.1.101的1~500端口进行一次TCP半开扫描,可以使用如图所示的命令:
import nmap
nm = nmap. PortScanner( )
nm . scan ( " 192.168.1.101", " 1-500" , "-ss")


all_hosts() #返回一个被扫描的所有主机列表


command_line() #返回在当前扫描中使用的命令行


csv() #返回值是一个CSV(逗号分隔值文件格式)的输出;如果希望返回结果更清楚,可以用print(nm.csv())。


has_host(self, host) #检查是否有host的扫描结果,有True,无False


scaninfo() #列出一个扫描信息的结构,该类还支持如下操作:
nm['192.168.1.101'].hostname() #获取192.168.1.101的主机名,通常为用户记录。
nm['192.168.1.101'].state() #获取主机192.168.1.101的状态(up|down|unknown|skipped)。
nm['192.168.1.101'].all_protocols() #获取执行的协议['tcp', 'udp']包含(IP|TCP|UDP|SCTP)。
nm['192.168.1.101'] ['tcp'].keys() #获取TCP所有的端口号。
nm['192.168.1.101'].all_tcp() #获取TCP所有的端口号(按照端口号大小进行排序)。
nm['192.168.1.101'].all_udp() #获取UDP所有的端口号(按照端口号大小进行排序)。
nm['192.168.1.101'].all_sctp() #获取SCTP所有的端口号(按照端口号大小进行排序)。
nm['192.168.1.101'].has_tcp(22) #主机192.168.1.101是否有关于22端口的任何信息。
nm['192.168.1.101'] ['tcp'][22] #获取主机192.168.1.101关于22端口的信息。
nm['192.168.1.101'].tcp(22) #获取主机192.168.1.101关于22端口的信息。
nm['192.168.1.101'] ['tcp'][22]['state'] #获取主机22端口的状态(open)。


-----------------------PortScannerAsync类-----------------------

#PortScannerAsync类和PortScanner类的功能很相似,但这个类可以实现异步扫描。
scan() #这个函数的完整形式为:
scan(self, hosts='127.0.0.1', ports=None, arguments='-sV',call_back =None, sudo=False)
#比PortScanner类中的sacn()函数多了一个回调参函数call_back(一个以(host, scan_data)为参数的函数)。

still_scanning()  #若扫描正在进行则返回True,否返回False

wait(self, timeout=None#表示等待时间

stop() #停止当前扫描

(1)在pycharm中安装这个模块
在这里插入图片描述

(2)查主机ip并在kali扫一下看一看
在主机打开cmd->输入“ipconfig”->找一个ipv4地址试一试
然后就在kali中新开一个终端,输入“sudo nmap ip地址
在这里插入图片描述
(3)在pycharm中写一写,快乐一下~
在这里插入图片描述
(4) 使用python-nmap模块编写简单扫描器
扫描器1:端口扫描器

import nmap

target= "192.168.66.1"
port= "80"
nm = nmap.PortScanner()
nm.scan(target,port)
for host in nm.all_hosts():
    print("__________________________________")
    print('Host:{0}({1})'.format(host, nm[host].hostname()))
    print('State:{0}'.format(nm[host].state()))
    for proto in nm[host].all_protocols():
        print("____________")
        print('Protocol:{0}'.format(proto))
        lport = list(nm[host][proto].keys())
        lport.sort()
        for port in lport:
            print('Port:{0} \t state:{1}'.format(port,nm[host][proto][port]['state']))

运行结果:

/root/PycharmProjects/socketProject/venv/bin/python /root/PycharmProjects/socketProject/nmapwhoistest.py
__________________________________
Host:192.168.66.1()
State:up
____________
Protocol:tcp
Port:80 	 state:filtered

(5)扫描器2:查看某网段有多少台终端设备(如果只希望扫描活跃主机,可用这个)

import nmap
nm = nmap. PortScanner()
nm.scan(hosts='192.168.0.0/24', arguments='-sP')
hosts_list = [(x, nm[x]['status']['state']) for x in nm.all_hosts()]
for host, status in hosts_list:
	print(host+" is "+status)

运行结果:

/root/PycharmProjects/socketProject/venv/bin/python /root/PycharmProjects/socketProject/nmaphosttest.py
192.168.0.0 is up
192.168.0.1 is up
192.168.0.10 is up
192.168.0.100 is up
192.168.0.101 is up
192.168.0.102 is up
192.168.0.103 is up
192.168.0.104 is up
192.168.0.105 is up
192.168.0.106 is up
192.168.0.107 is up
192.168.0.108 is up
192.168.0.109 is up
192.168.0.11 is up
192.168.0.110 is up
192.168.0.111 is up
192.168.0.112 is up
192.168.0.113 is up
192.168.0.114 is up
192.168.0.115 is up
192.168.0.116 is up
192.168.0.117 is up
192.168.0.118 is up
192.168.0.119 is up
192.168.0.12 is up
192.168.0.120 is up
192.168.0.121 is up
192.168.0.122 is up
192.168.0.123 is up
192.168.0.124 is up
192.168.0.125 is up
192.168.0.126 is up
192.168.0.127 is up
192.168.0.128 is up
192.168.0.129 is up
192.168.0.13 is up
192.168.0.130 is up
192.168.0.131 is up
192.168.0.132 is up
192.168.0.133 is up
192.168.0.134 is up
192.168.0.135 is up
192.168.0.136 is up
192.168.0.137 is up
192.168.0.138 is up
192.168.0.139 is up
192.168.0.14 is up
192.168.0.140 is up
192.168.0.141 is up
192.168.0.142 is up
192.168.0.143 is up
192.168.0.144 is up
192.168.0.145 is up
192.168.0.146 is up
192.168.0.147 is up
192.168.0.148 is up
192.168.0.149 is up
192.168.0.15 is up
192.168.0.150 is up
192.168.0.151 is up
192.168.0.152 is up
192.168.0.153 is up
192.168.0.154 is up
192.168.0.155 is up
192.168.0.156 is up
192.168.0.157 is up
192.168.0.158 is up
192.168.0.159 is up
192.168.0.16 is up
192.168.0.160 is up
192.168.0.161 is up
192.168.0.162 is up
192.168.0.163 is up
192.168.0.164 is up
192.168.0.165 is up
192.168.0.166 is up
192.168.0.167 is up
192.168.0.168 is up
192.168.0.169 is up
192.168.0.17 is up
192.168.0.170 is up
192.168.0.171 is up
192.168.0.172 is up
192.168.0.173 is up
192.168.0.174 is up
192.168.0.175 is up
192.168.0.176 is up
192.168.0.177 is up
192.168.0.178 is up
192.168.0.179 is up
192.168.0.18 is up
192.168.0.180 is up
192.168.0.181 is up
192.168.0.182 is up
192.168.0.183 is up
192.168.0.184 is up
192.168.0.185 is up
192.168.0.186 is up
192.168.0.187 is up
192.168.0.188 is up
192.168.0.189 is up
192.168.0.19 is up
192.168.0.190 is up
192.168.0.191 is up
192.168.0.192 is up
192.168.0.193 is up
192.168.0.194 is up
192.168.0.195 is up
192.168.0.196 is up
192.168.0.197 is up
192.168.0.198 is up
192.168.0.199 is up
192.168.0.2 is up
192.168.0.20 is up
192.168.0.200 is up
192.168.0.201 is up
192.168.0.202 is up
192.168.0.203 is up
192.168.0.204 is up
192.168.0.205 is up
192.168.0.206 is up
192.168.0.207 is up
192.168.0.208 is up
192.168.0.209 is up
192.168.0.21 is up
192.168.0.210 is up
192.168.0.211 is up
192.168.0.212 is up
192.168.0.213 is up
192.168.0.214 is up
192.168.0.215 is up
192.168.0.216 is up
192.168.0.217 is up
192.168.0.218 is up
192.168.0.219 is up
192.168.0.22 is up
192.168.0.220 is up
192.168.0.221 is up
192.168.0.222 is up
192.168.0.223 is up
192.168.0.224 is up
192.168.0.225 is up
192.168.0.226 is up
192.168.0.227 is up
192.168.0.228 is up
192.168.0.229 is up
192.168.0.23 is up
192.168.0.230 is up
192.168.0.231 is up
192.168.0.232 is up
192.168.0.233 is up
192.168.0.234 is up
192.168.0.235 is up
192.168.0.236 is up
192.168.0.237 is up
192.168.0.238 is up
192.168.0.239 is up
192.168.0.24 is up
192.168.0.240 is up
192.168.0.241 is up
192.168.0.242 is up
192.168.0.243 is up
192.168.0.244 is up
192.168.0.245 is up
192.168.0.246 is up
192.168.0.247 is up
192.168.0.248 is up
192.168.0.249 is up
192.168.0.25 is up
192.168.0.250 is up
192.168.0.251 is up
192.168.0.252 is up
192.168.0.253 is up
192.168.0.254 is up
192.168.0.255 is up
192.168.0.26 is up
192.168.0.27 is up
192.168.0.28 is up
192.168.0.29 is up
192.168.0.3 is up
192.168.0.30 is up
192.168.0.31 is up
192.168.0.32 is up
192.168.0.33 is up
192.168.0.34 is up
192.168.0.35 is up
192.168.0.36 is up
192.168.0.37 is up
192.168.0.38 is up
192.168.0.39 is up
192.168.0.4 is up
192.168.0.40 is up
192.168.0.41 is up
192.168.0.42 is up
192.168.0.43 is up
192.168.0.44 is up
192.168.0.45 is up
192.168.0.46 is up
192.168.0.47 is up
192.168.0.48 is up
192.168.0.49 is up
192.168.0.5 is up
192.168.0.50 is up
192.168.0.51 is up
192.168.0.52 is up
192.168.0.53 is up
192.168.0.54 is up
192.168.0.55 is up
192.168.0.56 is up
192.168.0.57 is up
192.168.0.58 is up
192.168.0.59 is up
192.168.0.6 is up
192.168.0.60 is up
192.168.0.61 is up
192.168.0.62 is up
192.168.0.63 is up
192.168.0.64 is up
192.168.0.65 is up
192.168.0.66 is up
192.168.0.67 is up
192.168.0.68 is up
192.168.0.69 is up
192.168.0.7 is up
192.168.0.70 is up
192.168.0.71 is up
192.168.0.72 is up
192.168.0.73 is up
192.168.0.74 is up
192.168.0.75 is up
192.168.0.76 is up
192.168.0.77 is up
192.168.0.78 is up
192.168.0.79 is up
192.168.0.8 is up
192.168.0.80 is up
192.168.0.81 is up
192.168.0.82 is up
192.168.0.83 is up
192.168.0.84 is up
192.168.0.85 is up
192.168.0.86 is up
192.168.0.87 is up
192.168.0.88 is up
192.168.0.89 is up
192.168.0.9 is up
192.168.0.90 is up
192.168.0.91 is up
192.168.0.92 is up
192.168.0.93 is up
192.168.0.94 is up
192.168.0.95 is up
192.168.0.96 is up
192.168.0.97 is up
192.168.0.98 is up
192.168.0.99 is up

Process finished with exit code 0

3、Scapy模块
Scapy是一个强大工具,可以使用这个模块来实现对网络数据包的发送、监听和解析,这个模块相较于nmap来说更为底层。可以更直观的了解网络中的各类扫描攻击行为。它已经在内部集成了大量网络协议的实现(如DNS、ARP、IP、TCP、UDP等)。
Scapy模块只会把收到的数据包展示给你,并不会告诉你这个包意味着什么。例如,当你去医院检查身体时,医院会给你一份关于身体各项指标的检查结果,而医生也会告诉你得了什么病或者没有任何病。那么Nmap就像是一个医生,它会替你搞定,按照它的经验提供给你结果。而Scapy则像是一个体检的设备, 它只会告诉你各种检查的结果,如果你自己就是一个经验丰富的医生,显然检查的结果要比同行的建议更值得参考。
(1)基本用法
启动scapy环境——直接在终端输入scapy即可
在这里插入图片描述
实例化协议类(以IP为例)——
1)创建IP类型数据包

>>> ip=IP()

2)构造一个发往“198.168.66.1”的IP数据包
IP数据包最重要的属性就是源地址和目的地址,这两个属性可以使用src和dst来设置,目的为“192.168.1.107”的数据包,可以这么写:

>>> ip=IP(dst="192.168.66.1")
#可以用如下命令查看ip数据包
>>> ip
<IP  dst=192.168.66.1 |>#结果

2)构造一个发往“198.168.66.0/24”的IP数据包
可以查看“198.168.66.0/24”地址范围的数据包,此时数据包就不只一个了,应该有256个。

>>> target="192.168.66.0/24"
>>> ip2 = IP(dst=target)
>>> ip2
<IP  dst=Net('192.168.66.0/24') |>#这里相当于输出的是一个集合,想看其中每个数据包的话,用下面的语句
>>> [p for p in ip2]
[<IP  dst=192.168.66.0 |>,
 <IP  dst=192.168.66.1 |>,
 <IP  dst=192.168.66.2 |>,
 <IP  dst=192.168.66.3 |>,
 <IP  dst=192.168.66.4 |>,
......#这里省略了显示的245个ip2中的ip数据包
 <IP  dst=192.168.66.251 |>,
 <IP  dst=192.168.66.252 |>,
 <IP  dst=192.168.66.253 |>,
 <IP  dst=192.168.66.254 |>,
 <IP  dst=192.168.66.255 |>

3)产生一个广播包
Scapy采用分层的形式来构造数据包,通常最下面的一个协议为Ether,然后是IP,在之后是TCP或者UDP。IP()函数无法用来构造ARP请求和应答数据包,所以这时可以使用Ether(),这个函数可以设置发送方和接收方的MAC地址。那么现在来产生一个广播数据包,执行的命令如下:

>>> Ether(dst="ff:ff:ff:ff:ff:ff")
<Ether  dst=ff:ff:ff:ff:ff:ff |>

分层用符号“/”实现,一个数据包由多层协议组合而成的,这些协议间可以用“/”分隔开。
例如-----构造一个TCP数据包:

>>> Ether()/IP()/TCP()
<Ether  type=IPv4 |<IP  frag=0 proto=tcp |<TCP  |>>>

又如----构造一个HTTP数据包:

>>> IP()/TCP()/"GET /HTTP/1.0\r\n\r\n"
<IP  frag=0 proto=tcp |<TCP  |<Raw  load='GET /HTTP/1.0\r\n\r\n' |>>>

4)ls()函数看属性
Scapy目前使用频率最高的类要数Ether、IP、TCP和UDP,但是这些类都具有哪些属性呢?Ether类中显然要有源地址、目的地址和类型。IP类的属性则复杂了许多,除了最重要的源地址和目的地址之外,还有版本、长度、协议类型、校验和等,TCP类中需要有源端口和目的端口。这里可以使用 ls() 函数来查看一个类拥有那些属性。

>>> ls(Ether()) #查看Ether()属性的语句
WARNING: Mac address to reach destination not found. Using broadcast.
dst        : DestMACField                        = 'ff:ff:ff:ff:ff:ff' (None)
src        : SourceMACField                      = '00:0c:29:af:cd:93' (None)
type       : XShortEnumField                     = 36864           (36864)


>>> ls(IP())
version    : BitField  (4 bits)                  = 4               (4)
ihl        : BitField  (4 bits)                  = None            (None)
tos        : XByteField                          = 0               (0)
len        : ShortField                          = None            (None)
id         : ShortField                          = 1               (1)
flags      : FlagsField  (3 bits)                = <Flag 0 ()>     (<Flag 0 ()>)
frag       : BitField  (13 bits)                 = 0               (0)
ttl        : ByteField                           = 64              (64)
proto      : ByteEnumField                       = 0               (0)
chksum     : XShortField                         = None            (None)
src        : SourceIPField                       = '127.0.0.1'     (None)
dst        : DestIPField                         = '127.0.0.1'     (None)
options    : PacketListField                     = []              ([])


>>> ls(TCP())
sport      : ShortEnumField                      = 20              (20)
dport      : ShortEnumField                      = 80              (80)
seq        : IntField                            = 0               (0)
ack        : IntField                            = 0               (0)
dataofs    : BitField  (4 bits)                  = None            (None)
reserved   : BitField  (3 bits)                  = 0               (0)
flags      : FlagsField  (9 bits)                = <Flag 2 (S)>    (<Flag 2 (S)>)
window     : ShortField                          = 8192            (8192)
chksum     : XShortField                         = None            (None)
urgptr     : ShortField                          = 0               (0)
options    : TCPOptionsField                     = []              (b'')

(2)常用函数
1)send()和sendp()
这两个函数的区别在于send()工作在第三层,而sendp()工作在第二层。 send()是用来发送IP数据包的,而sendp()是用来发送Ether数据包的。
例如,构造一个目的地址为“192.168.88.129”的ICMP数据包,并将其发送出去,可以使用语句send(IP(dst="192.168.88.129")/ICMP())

>>> send(IP(dst="192.168.88.129")/ICMP())
---------------------------------------------------------------------------
PermissionError                           Traceback (most recent call last)
<ipython-input-22-38e87838d0bf> in <module>
----> 1 send(IP(dst="192.168.88.129")/ICMP())

/usr/lib/python3/dist-packages/scapy/sendrecv.py in send(x, inter, loop, count, verbose, realtime, return_packets, socket, iface, *args, **kargs)
    343     need_closing = socket is None
    344     kargs["iface"] = _interface_selection(iface, x)
--> 345     socket = socket or conf.L3socket(*args, **kargs)
    346     results = __gen_send(socket, x, inter=inter, loop=loop,
    347                          count=count, verbose=verbose,

/usr/lib/python3/dist-packages/scapy/arch/linux.py in __init__(self, iface, type, promisc, filter, nofilter, monitor)
    396                 "The 'monitor' argument has no effect on native linux sockets."
    397             )
--> 398         self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type))  # noqa: E501
    399         if not nofilter:
    400         if conf.except_filter:

/usr/lib/python3.10/socket.py in __init__(self, family, type, proto, fileno)
    230             if proto == -1:
    231                 proto = 0
--> 232         _socket.socket.__init__(self, family, type, proto, fileno)
    233         self._io_refs = 0
    234         self._closed = False

PermissionError: [Errno 1] Operation not permitted

问题:刚开始报错了,然后退出scapy,用sudo scapy进入,运行同样的命令,发送成功

>>> send(IP(dst="192.168.88.129")/ICMP())
.
Sent 1 packets.
>>> sendp(Ether(dst="ff:ff:ff:ff:ff:ff"))
.
Sent 1 packets.

注意:这两个函数的特点是 只发不收,只会将数据包发送出去,但是没有能力处理该数据包的回应包!!

2)fuzz()函数
如果希望发送一个 内容是随机填充 的数据包,而且又要保证这个数据包的正确性,那么可以用 fuzz( ) 函数。创建一个发往192.168.88.129的、TCP数据包可用如下命令

>>> IP(dst='192.168.88.129')/fuzz(TCP())
<IP  frag=0 proto=tcp dst=192.168.88.129 |<TCP  |>>

3)sr()、sr1()和srp()
在Scapy中提供了三个用来 发送和接收数据包的函数,分别是sr()、sr1()和srp(),其中,sr()和sr1()主要用于第三层,例如IP和ARP等。而srp()用于第二层。
用sr()向192.168.88.1发送一个ICMP数据包。可发现,Scapy会监听接收到的数据包,并筛选出对应的应答数据包作为结果显示出来。Received 表示收到的数据包个数, answers表示对应的应答数据包。

>>> ans,unans=sr(IP(dst='192.168.66.1')/ICMP())
Begin emission:
Finished sending 1 packets.
.*
Received 2 packets, got 1 answers, remaining 0 packets
>>> ans.summary()
IP / ICMP 192.168.88.129 > 192.168.66.1 echo-request 0 ==> IP / ICMP 192.168.66.1 > 192.168.88.129 echo-reply 0 / Padding
>>> unans.summary()   #成功应答,所以第二个列表没有值
>>> ans1,unans1=sr(IP(dst='192.168.88.129')/ICMP())
Begin emission:
Finished sending 1 packets.
.^C#因为没有成功收到应答,所以一直没有结束,我就按了ctrl+C让它早点结束,早点看结果
Received 1 packets, got 0 answers, remaining 1 packets
>>> unans1.summary()
IP / ICMP 192.168.88.129 > 192.168.88.129 echo-request 0
>>> ans1.summary() #没有成功应答,所以第一个列表中没有值

注意:Reveived表示收到的数据包个数,answers表示对应的应答数据包。sr()函数是Scapy的核心,它的返回值是两个列表ans和unans,第一个列表是收到了应答的包和对应的应答,第二个列表是未收到应答的包。所以可以使用两个列表来保存 sr() 的返回值。

sr1()函数和sr()函数作用基本一样,但是值返回一个应答包。只需要使用一个列表就可以保存这个函数的返回值。例如,使用p来保存`sr1(IP(dst=“192.168.1.107”)/ICMP())`的返回值。
可以使用sr1()函数来测试目标的某个端口是否开放,采用半开扫描(SYN)的办法。
从上面p的值可以看出,192.168.1.107回应了发出设置了SYN标志位的TCP数据包,这表明他开放了80端口
>>> p=sr1(IP(dst="192.168.66.1")/ICMP())
Begin emission:
Finished sending 1 packets.
.*
Received 2 packets, got 1 answers, remaining 0 packets
>>> p
<IP  version=4 ihl=5 tos=0x0 len=28 id=4396 flags= frag=0 ttl=128 proto=icmp chksum=0xde2 src=192.168.66.1 dst=192.168.88.129 |<ICMP  type=echo-reply code=0 chksum=0xffff id=0x0 seq=0x0 |<Padding  load='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |>>>
>>> p1=sr1(IP(dst="127.0.0.1")/TCP(dport=22,flags="S"))
Begin emission:
Finished sending 1 packets.
.^C
Received 1 packets, got 0 answers, remaining 1 packets
>>> p1

#因为80端口没开,所以获取不到,暂时我也不知道怎么开启端口。网上找了一下教程,没有成功,哎。
#但是,如果成功的话,p1应该是有数据的。而且它会正常扫描结束
#比如我扫了一下百度官网,命令与结果如下
>>> p1=sr1(IP(dst="www.baidu.com")/TCP(dport=80,flags="S"))
Begin emission:
Finished sending 1 packets.
.*
Received 2 packets, got 1 answers, remaining 0 packets
>>> p1
<IP  version=4 ihl=5 tos=0x0 len=44 id=4705 flags= frag=0 ttl=128 proto=tcp chksum=0x4f43 src=14.215.177.39 dst=192.168.88.129 |<TCP  sport=http dport=ftp_data seq=1026839284 ack=1 dataofs=6 reserved=0 flags=SA window=64240 chksum=0x3370 urgptr=0 options=[('MSS', 1460)] |<Padding  load='\x00\x00' |>>>

4)sniff()
这个函数可以在自己的程序中捕获经过本机网卡的数据包。
✦指定只捕获与192.168.88.129有关的数据包,可以使用:sniff(filter=" host 192.168.88.129")
✦同样,也可以使用filter来过滤指定协议,例如,icmp类型的数据包:sniff(filter="icmp")
✦如果要同时满足多个条件可以使用“and”“or”等关系运算符来表达:sniff(filter=" host 192.168.88.129 and icmp")
✦另外两个很重要的参数是iface、count。iface可以用来指定所要进行监听的网卡,count则用来指定监听到数据包的数量,达到指定的数量就会停止监听。

>>> sniff(filter="icmp and  host 192.168.66.1",count=3,iface="eth0")
<Sniffed: TCP:0 UDP:0 ICMP:3 Other:0>
>>> 
>>> a=_    #“_”表示上一条语句执行的结果,这里就能看到刚刚sniff抓到的三个包的结果
>>> a.nsummary()
0000 Ether / IP / ICMP 192.168.88.129 > 192.168.66.1 echo-request 0 / Raw
0001 Ether / IP / ICMP 192.168.66.1 > 192.168.88.129 echo-reply 0 / Raw
0002 Ether / IP / ICMP 192.168.88.129 > 192.168.66.1 echo-request 0 / Raw

#区分:nsmammry()是显示多条结果,summary()是显示一条结果
>>> p3=IP(dst="www.baidu.com")
>>> p3.summary()
"192.168.88.129 > Net('www.baidu.com') hopopt"

在这里插入图片描述
(3)简单实例
由于scapy功能极为强大,可以构造目前各种常见的协议类型的数据包,因此几乎可以使用这个模块完成任何任务,下面看看一些简单的应用。
1)使用scapy实现一次ACK类型的端口扫描
192.168.88.12921、22、23、135、443、445这些端口是否被屏蔽进行扫描, 注意是屏蔽,不是关闭! 采用ACK扫描模式:

>>> ans,unans = sr(IP(dst="192.168.66.1")/TCP(dport=[21,22,23,135,443,445],flags
...: ="A"))
Begin emission:
Finished sending 6 packets.
.******
Received 7 packets, got 6 answers, remaining 0 packets

正常的时候,如果一个开放的端口会回应ACK数据包,而关闭则回应RST数据包。在网络中,一些安全设备会过滤一部分端口,这些端口不会响应来自外界的数据包一切发往这些端口的数据包都石沉大海,这些端口的状态并非是开放或者关闭的这是网络安全管理常用的方法。

2)查看未被过滤与被过滤的端口
向目标发送5个标志位为“A”的TCP数据包,按照TCP三次握手规则,如果目标端口没有被过滤,发出的数据包就会得到回应,否则没有回应。另外根据Scapy的设计,ans列表中的数据包就是得到回应的数据包,而unans中的则是没有得到回应的数据包。只需要分两次读取这两个列表就能得到端口过滤结果。
首先查看未被过滤的端口

>>>  for s,r in ans:
...:     if s[TCP].dport == r[TCP].sport:
...:         print("The port "+str(s[TCP].dport)+" is unfiltered")
...: 
The port 21 is unfiltered
The port 22 is unfiltered
The port 23 is unfiltered
The port 135 is unfiltered
The port 443 is unfiltered
The port 445 is unfiltered

再查看被过滤的端口,发现为空。

>>>  for s in unans:
...:         print("The port "+str(s[TCP].dport)+" isfiltered")
...: 

3)编写端口扫描器
下面使用Scapy强大的包处理功能来设计一个端口是否开放的扫描器。注意,这里还是要注意和前面例子的区别,如果-一个端口处于屏蔽状态,那么它将不会产生任何响应报文。如果一个端口处于开放状态,那么它在收到syn数据包之后,就会回应一个ack数据包。反之,如果一个端口处于关闭状态,那么它在收到syn数据包之后,就会回应一个rst数据包。首先在Kali Linux 2中启动一个终端,在终端中打开Python。
先导入需要使用的模块文件:from scapy.all import fuzz,TCP,IP,sr #导入模块与函数
接下来产生一个目标为“192.168.66.1”的80端口的SYN数据包,将此标志位设置为“S”:

>>> ans,unans = sr(IP(dst="192.168.66.1")/fuzz(TCP(dport=80,flags="S")))
Begin emission:
Finished sending 1 packets.
.*
Received 2 packets, got 1 answers, remaining 0 packets

接下来使用循环查看,如果r[TCP].flags==18,则表示目标端口开放,若为20则为关闭状态。

>>> for s,r in ans: #把ans的值赋给s,r并开始遍历
...:      if r[TCP].flags==18: 	#判断返回值是否等于18
...:          print("This port is Open")   #输出判断结果:开放
...:      if r[TCP].flags==20:   	#判断返回值是否等于20
...:          print("This port is Closed")  	#输出判断结果:关闭
...: 
This port is Closed

猜你喜欢

转载自blog.csdn.net/weixin_49422491/article/details/125036281