安全渗透测试常见模块【Socket模块】【python-nmap模块】【Scapy模块】


Python是一个非常强大的网络安全渗透语言。

Python中与网络相关的模块:

  • Socket模块

  • python-nmap模块

  • Scapy模块

Socket模块

Socket并不是TCP/IP协议族中的协议,而是一个编程接口。Socket正是TCP/IP提供的外部接口。

Socket是对TCP/IP的封装和应用。

Socket被称作“套接字”,用于描述IP地址和端口,是一个通信、链的句柄,可以实现不同虚拟机 或不同计算机之间的通信。网络上的两个程序通过一个双向的通信连接实现数据的交换,应用程序通过“套接字”向网络发出请求或者应答网络请求。

简介

Socket模块的主要目的是帮助在网络上的两个程序之间建立信息通道。在Python中提供了两个基本的Socket模块:

  • 服务端Socket

  • 客户端Socket

当创建一个服务端Socket之后,这个Socket就会在本机的一个端口上等待连接,客户端Socket会访问这个端口,当两者完成连接之后,就可以进行交互了。

基本用法

1、Socket实例化

Socket实例化格式

socket(family,type[,protocal])

family:地址族,常用地址族有AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX、UNIX域Socket)、AF_ROUTE等。默认为AF_INET,通常使用默认即可。

type:Socket类型

SOCK_STREAM,TCP类型(默认)

SOCK_DGRAM,UDP类型

SOCK_RAM,原始类型,允许对底层协议如IP或ICMP进行直接访问,基本用不到。

protocal:使用的协议,通常赋值“0”,由系统自动选择。

#初始化一个TCP类型的Socket   
s=socket.socket()

#初始化一个UDP类型的Socket
s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 

2、Socket常用函数

bind()

由服务端Socket()调用,会将之前创建Socket与指定的IP地址和端口进行绑定。

#将创建的Socket套接字绑定到本机的2345端口
s.bind(("127.0.0.1",2345))

listen()

用于在使用TCP的服务端开启监听模式。

#服务端开启一个监听,最大连接数为5
s.listen(5) 

accept()

用于在使用TCP的服务端接收连接,一般是阻塞态。接受TCP连接并返回(conn, adress),其中conn为新的套接字对象,可以用来接收和发送数据,address为连接客户端的地址。

connect()

用于在使用TCP的客户端去连接服务端时使用

# 连接本机的2345端口
s.connect(("127.0.0.1",2345)) 

send()

用于在使用TCP时发送数据,可能未将指定的内容全部发送。

send(string[,flag])   #返回值是发送字节数量

sendall()

用于在使用TCP时发送数据,完整发送TCP数据。

# 发送一段字符到Socket
s.sendall(bytes("Hello!", encoding="utf-8"))
# 成功返回None,失败抛出异常 

recv()

用于使用TCP接收数据

recv(bufsize[,flag])
# bufsize指定最多可以接收的数量

#接收一段长度为1024 的字符Socket
obj.recv(1024) 

sendto()

用于使用UDP时发送数据

recvfrom()

UDP专用,接收数据,返回远端的IP地址和端口

close():关闭Socket。

3、使用Socket编写一个简单的服务端和客户端

服务端程序

import socket
s1 = socket.socket()
s1.bind(("127.0.0.1",2345))
s1.listen(5)
while 1:
  conn,address = s1.accept()
  print("a new connect from",address)
  conn.sendall("Hello world")
  conn.close() 

客户端程序

import socket
s2 = socket.socket()
s2.connect(("127.0.0.1",2345))
message = input("请输入信息:")
s2.send(message.encode())
data = s2.recv(1024)
s2.close()
print("Received",repr(data)) 

python-nmap模块

Nmap是网络安全审计工具,可以通过对设备的探测来审计它的安全性。

Nmap的功能

  1. 主机发现功能。向目标主机发送信息,然后根据目标的反应来确定它是否处于开机并联网状态。

  2. 端口扫描。向目标计算机的制定端口发送信息,然后根据目标端口的反应来判断它是否开放。

  3. 服务及版本检测。向目标计算机的目标端口发送特制的信息,然后根据目标的反应来检测它运行服务的服务类型和版本。

  4. 操作系统检测。

  5. 其他高级的审计技术。如:伪造发起扫描端的身份,进行隐蔽的扫描,规避目标的防御设备(例如防火墙),对系统进行安全漏洞检测,并提供完善的报告选项。

简介

python-nmap是一个可以帮助使用Nmap功能的Python模块文件。

如果想要在Python中正常使用python-nmap模块,必须现在系统中安装Namp。

基本用法

python-nmap模块的核心是PortScannerPortScannerAsyncPortScannerErrorPortScannerHostDictPortScannerYield 等5个类。

1、python-nmap模块类的实例化

nmap.PortScanner()

2、pyhon-nmap模块中的函数

Portscanner类中的函数

**scan()**函数:用来对指定目标进行扫描

scan(self,hosts="127.0.0.1",ports=None,arguments="-sV",sudo=False)

# **host****:**要扫描的主机
# **ports**:要扫描的端口
    ## 单一端口:“80”
    ## 多个端口:“80,443,8080”
    ## 端口范围:“1-1000”
# **arguments**:Nmap扫描时所使用的的参数
    ## -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()函数:**返回一个被扫描的所有主机列表

>>> nm.all_hosts()
["192.168.1.101"] 

**command_line()**函数:返回在当前扫描中使用的命令行

>>> nm.command_line()
'nmap -oX - -p 1-500 -sS 192.168.1.101' 

**csv()**函数:返回一个CSV(逗号分隔值文件格式)的输出

>>> nm.csv()
>>> print(nm.csv()) 

**has_host(self,host)**函数:检查是否有host的扫描结果,如果有则返回True,否则返回False

>>> nm.has_host("192.168.1.101")
True 

**scaninfo()**函数:列出一个扫描信息的结构

>>> nm.scaninfo()od
{"tcp":{"servers":"1-500","method":"syn"}} 

这个类还支持如下的操作:

nm["192.168.1.101"].hostname()  # 获取主机名,通常为用户记录
nm["192.168.1.101"].state()    # 获取主机的状态
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)   # 主机是否有关于22端口的信息
nm["192.168.1.101"]["tcp"][22]  # 获取主机关于22端口的信息 
nm["192.168.1.101"].tcp(22)   # 获取主机关于22端口的信息
nm["192.168.1.101"]["tcp"][22]["state"]  # 获取主机22端口的状态
nm["192.168.1.101"]
nm["192.168.1.101"]
nm["192.168.1.101"] 

PortScannerAsync类中的函数

PortScannerAsync类中的函数scan()与PortScanner类中的scan()基本一样,但是多了一个回调函数。

scan(self,host="127.0.0.1",ports=None,arguments="-sV",callback=None,sudo=False)
# callback是以(host,scan_data)为参数的函数
import namp
nma = nmap.PortScannerAsync()
nma.scan(hosts="192.168.1.0/24",arguments="-sP") 

still_scanning():如果扫描正在进行,则返回True,否则返回False

wait(self,timeout=None):函数表示等待时间

stop():停止当前的扫描

3、使用python-nmap模块来编写一个扫描器

扫描192.168.1.101开放的从1~1000的哪些端口

import nmap
nm = nmap.PortScanner()
nm.scan("192.168.1.101","1-1000")
for host in nm.all_hosts():
    print("*"*30)
    print("Host:%s(%s)"%(host,nm[host].honstname()))
    print("State:%s"%nm[host].state())
    for proto in nm[host].all_protocols():
        print("*"*30)
        print('Protocol:%s'%proto)
        lport = nm[host][proto].keys()
        lport.sort()
        for port in lport:
            print('port:%s\state:%s'%(port,nm[host][proto][port]['state'])) 
nma = nmap.PortScannerAsync()
def callback_result(host,scan_result):
    print() 
    print(host,scan_result)

nma.scan(hosts="192.168.1.0/24",arguments="-sP",callback_result) 

在使用scan函数扫描的过程中会执行callback_result函数,可以一边扫描一边输出扫描结果。

Scapy模块

简介

Scapy的内部实现了大量的网络协议(DNS、ARP、IP、TCP、UDP等),可以实现对网络数据包的发送、监听和解析。这个模块相比与Nmap来说,更加底层。可以更为直观的了解到网络中的各种扫描和攻击行为。

基本用法

Scapy本身就是一个可以运行的工具,它自己具备一个独立的运行环境,因而可以不在Python环境下运行。

1、Scapy的基本操作

在Scapy中,每一个协议就是一个类。只需要实例化一个协议类,就可以创建一个该协议的数据包。

例如,如果要创建一个IP类型的数据包,就可以使用如下命令:

>>> ip = IP()
>>> ip
<IP > 

构造一个发往“192.168.1.101”的IP数据包

>>> ip = IP(dst="192.168.1.101")
>>> ip
<ip dst=192.168.1.101 > 

这个dst的值可以是一个IP地址,也可以是一个IP范围,例如192.168.1.0/24,这时产生的不是一个数据包,而是256个数据包。

>>> target = "192.168.1.0/24"
>>> ip = IP(dst=target)
>>> ip
<ip dst=Net("192.168.1.0/24") > 

# 查看其中每一个数据包,可以使用[p for p in ip]
>>> [p for p in ip] 

Scapy采用分层的形式来构造数据包,通常最下面的一个协议为Ether,然后是IP,再之是TCP或者是UDP。IP()函数无法构造ARP请求和应答数据包,但可以使用Ether()

# 构造一个广播数据包
>>> Ether(dst="ff:ff:ff:ff:ff:ff")
<Ether dst=ff:ff:ff:ff:ff:ff> 

Scapy中的分层通过符号/ 实现,按照协议由底而上的顺序从左向右排列,例如:

>>> Ether()/IP()/TCP()

构造一个HTTP数据包

>>> IP()/TCP()/"GET / HTTP/1.0\r\n\r\n"

使用ls()函数来查看一个类所拥有的属性

# 查看Ether类的属性
>>> ls(Ether()) 

2、Scapy模块中的函数

Scapy中提供了许多用来完成发送数据包的函数。

✨ send(),sendp()

**send()**工作在第三层,用来发送IP数据包;

**sendp()**工作在的二层,用来发送Enter数据包。

例如:构造一个目的地址为“192.168.1.101”的ICMP数据包,并将其发送出去。

>>> send(IP(dst="192.168.1.101")/ICMP())
Sent 1 packets.

>>> sendp(Ether(dst="ff:ff:ff:ff:ff:ff"))
Sent 1 packets. 

这两个函数的特点是只发不收。

fuzz()

如果希望发送一个内容是随机填充的数据包,而且又要保证这个数据包的正确性,可以使用fuzz() 函数。

如果不使用fuzz() 来填充数据包,这样有可能会导致目标端口不响应,从而无法对目标端口状态进行判断。

>>> IP(dst="192.168.1.101")/fuzz(TCP())
✨ sr(),sr1(),srp()

Scapy中提供了三个用来发送和接收的数据包的函数,分别是sr()sr1()srp() ,其中sr()sr1() 主要用于第三层,而srp() 用于第二层。

# 向127.0.0.1发送一个ICMP数据包
>>> sr(IP(dst="127.0.0.1")/ICMP()) 
Begin emission:
.Finished sending 1 packets.
^C
Received 1 packets, got 0 answers, remaining 1 packets
(<Results: TCP:0 UDP:0 ICMP:0 Other:0>,
 <Unanswered: TCP:0 UDP:0 ICMP:1 Other:0>) 

当产生的数据包发送出去之后,Scapy就会监听接收到的数据包,并将其中对应的数据包筛选出来,显示在下面。Reveived表示收到的数据包个数,answers表示对应的应答数据包。

sr()的返回值是两个列表,第一个列表是收到了应答的包和对应的应答,第二个列表是未收到应答的包。

>>> ans,unans = sr(IP(dst="192.168.120.3")/ICMP())                         
Begin emission:
Finished sending 1 packets.
.*
Received 2 packets, got 1 answers, remaining 0 packets
>>> ans.summary()                                                          
IP / ICMP 192.168.120.2 > 192.168.120.3 echo-request 0 ==> 
IP / ICMP 192.168.120.3 > 192.168.120.2 echo-reply 0 / Padding

sr1()函数跟sr()函数作用基本一样,但是只返回一个应答包。所以只需要使用一个列表就可以保存这个函数的返回值。

>>> p = sr1(IP(dst="192.168.120.3")/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=692 
flags= frag=0 ttl=128 proto=icmp chksum=0xc6d6 
src=192.168.120.3 dst=192.168.120.2 
|<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' |>>>  
>>> p.summary()                                                            
'IP / ICMP 192.168.120.3 > 192.168.120.2 echo-reply 0 / Padding'
>>>  

可以利用sr1()函数来测试目标的某个端口号是否开放,采用半开扫描(SYN)是办法。

>>> p1 = sr1(IP(dst="192.168.120.3")/TCP(dport=443,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=1692 flags=DF 
frag=0 ttl=128 proto=tcp chksum=0x82d9 src=192.168.120.3 dst=192.168.120.2 |
<TCP  sport=https dport=ftp_data seq=3559562169 ack=1 
dataofs=6 reserved=0 flags=SA window=65392 
chksum=0xb59a urgptr=0 options=[('MSS', 1460)] |
<Padding  load='\x00\x00' |>>>


从上面p的值可以看来,192.168.120.3回应了发送的设置了SYN标志位的TCP数据包,这表明这台主机的443端口是开放的。

✨ sniff()

sniff()函数,可以在自己的程序中捕获经过本机网卡的数据包。

>>> sniff()
^C<Sniffed: TCP:0 UDP:0 ICMP:8 Other:4>

使用sniff()开始监听,但是捕获的数据包不会即时显示,需要使用组合键Ctrl+C停止监听时,才能显示捕获的数据包。

此函数可以使用参数filter对数据包进行过滤。

# 针对IP进行过滤
>>> sniff(filter=" host 192.168.120.3")
# 针对指定协议进行过滤
>>> sniff(filter="icmp") 
# 同时满足多个条件使用“and”“or”等关系运算符来表达
>>> sniff(filter=" host 192.168.120.3 and icmp") 

参数iface可以用来指定所要进行监听的网卡

>>> sniff(iface="eth1")

参数count用来指定监听到数据包的数量,达到指定的数量就会停止监听

>>> sniff(count=3)

现在设计一个综合性的监听器,它会在网卡eth0上监听源地址或者目标地址为192.168.120.3的icmp数据包,当收到3个数据包之后,就会停止监听。

>>> sniff(filter="icmp and host 192.168.120.3", count=3, iface="eth0")
<Sniffed: TCP:0 UDP:0 ICMP:3 Other:0> 
>>> _                                     
<Sniffed: TCP:0 UDP:0 ICMP:3 Other:0>
>>> a=_                                      
>>> a
<Sniffed: TCP:0 UDP:0 ICMP:3 Other:0>
>>> a.summary()
Ether / IP / ICMP 192.168.120.3 > 192.168.120.2 echo-request 0 / Raw
Ether / IP / ICMP 192.168.120.2 > 192.168.120.3 echo-reply 0 / Raw
Ether / IP / ICMP 192.168.120.3 > 192.168.120.2 echo-request 0 / Raw
>>> a.nsummary()
0000 Ether / IP / ICMP 192.168.120.3 > 192.168.120.2 echo-request 0 / Raw
0001 Ether / IP / ICMP 192.168.120.2 > 192.168.120.3 echo-reply 0 / Raw
0002 Ether / IP / ICMP 192.168.120.3 > 192.168.120.2 echo-request 0 / Raw

如果需要查看这三个数据包的内容,可以使用_ ,在Scapy中这个符号表示的是上一条语句执行的结果。

函数pkt.nsummary()和pkt.summary()作用相同,只是要操作的对象是多个数据包。

3、Scapy模块的常用简单实例

检测端口是否被屏蔽

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

使用Scapy来实现一次ACK类型的端口扫描,例如:对192.168.120.3的21、23、135、443、445这5个端口是否被屏蔽进行扫描,采用ACK的扫描方式。

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

查看未被过滤的端口:

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

查看被过滤的端口:

>>> for s in unans: 
...:     print(str(s[TCP].dport)+"is filtered") 
...:

在Python中编写程序来实现查看端口是否被屏蔽

from scapy.all import IP,TCP,sr
ans,unans = sr(IP(dst="192.168.120.3")/TCP(dport=[21,23,135,443,445],flags="A"))
for s,r in ans:
     if s[TCP].dport == r[TCP].sport: 
         print("The port" + str(s[TCP].dport) + "is unfiltered")  

使用IP(),TCP()来创建数据包,使用fuzz()来填充数据包,使用sr()来发送数据包。

from scapy.all import fuzz,TCP,IP,sr
ans,unans = sr(IP(dst="192.168.120.3")/fuzz(TCP(dport=80,flags="S")))  

接下来使用循环来查看,如果r[TCP].flags == 18,则表示反会数据包flags的值为0x012(SYN,ACK),目标端口为开放状态。如果r[TCP].flags == 20,则表示反会数据包flags的值为0x014(RST,ACK),目标端口为关闭状态。

for s,r in ans:
  if r[TCP].flags == 18:
    print("This port is Open")
  if r[TCP].flags == 20:
    print("This port is Closed") 

在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值