600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > 菜鸟渗透日记30---python渗透测试编程之信息收集2-端口扫描

菜鸟渗透日记30---python渗透测试编程之信息收集2-端口扫描

时间:2024-05-14 16:55:42

相关推荐

菜鸟渗透日记30---python渗透测试编程之信息收集2-端口扫描

书接上文

菜鸟渗透日记29---python渗透测试编程之信息收集1-主机发现

目录

端口概念简介

基于TCP全开的端口扫描技术

TCP全开端口扫描原理

设计一个基于TCP全开的完整端口扫描程序

基于TCP半开的端口扫描技术

TCP半开端口扫描的原理

设计一个基于TCP半开的完整端口扫描程序

端口概念简介

上文提到端口扫描,这是在传输层才出现的概念,可以认为端口就是设备和外界进行交流的端口。例如,常见的用来完成FTP服务的21端口,常见的用来完成web服务的80端口等等。

端口扫描在网络安全渗透中是一个十分重要的概念。如果把服务器看作一个房子,那么端口就是通向不同房间(服务)的们。从入侵者角度来分析,我们如果要侵入这个房子,就需要知道这个房子有多少门,门后面有什么东西都是十分重要的内容

因此在信息收集阶段就需要对目标的端口开放情况做扫描,因为一方面这些端口可能成为进出的通道,另一方面利用这些端口有可以进一步获得目标主机上运行的服务,从而找到可以进行渗透的漏洞。

正常来说,端口只有open和closed两种状态,但是有时候会出现网络安全的机制屏蔽了端口的探测,因此该端口会出现无法判断的情况,所以在探测时候要为端口添加一个filtered状态,表示无法获悉目标端口的真正状态。

判断一个端口的状态在Nmap中继承了很多端口扫描的方法,这里只说两种常用的方法:TCP全开扫描和TCP半开扫描

基于TCP全开的端口扫描技术

TCP全开端口扫描原理

这种扫描的思想很简单,如果目标端口是开放的,那么在接到主机端口发出的SYN请求之后,就会返回一个SYN+ACK的包,然后主机端口再回应一个ACK,这样就成功地和目标端口建立了一次TCP链接。

过程如图:

如果目标端口是关闭的,那么再接收到主机端口发出的SYN请求之后,就会返回一个RST回应,表示不接受这次请求,这样就中断了这次TCP链接。

过程如图:

还有一种特殊情况,主机发送出SYN请求之后,没有收到任何回应。多种原因可能造成这种情况,例如,目标主机没有活跃、一些网络安全设备屏蔽掉端口的SYN请求。关于屏蔽这种情况暂时不考虑。

过程如图:

在前文中已经学习了Scapy中IP数据包和TCP数据包的格式,这里仅仅需要将TCP的flags参数设置为“S”,表明这是一个SYN请求的数据包,构造这个数据包的语句如下所示:

packet=IP(dst=dst_ip)/TCP(sport=src_port,flag=”S”)

然后使用sr1函数将这个数据包发送出去,并且设置5秒延迟。

resp = sr1(packet,timeout=5)

然后根据应答包来判断目标端口的状态,这时候的情况根据刚才的图,会有三种情况。

第一种:如果resp值为空,就表示没有收到来自目标的回应。在程序中可以使用str(type(resp))来判断这个resp是不是为空,当type(resp)的值转换为字符串之后为“<type ‘NoneType’>”时,表示resp为空,就是没有收到任何数据包,可以直接判断目标端口关闭,跳到后面的第二种或者第三种情况。

第二种:当收到了回应的数据包之后,判断一下这个数据包时“SYN+ACK”类型还是“RST”类型。在scapy模块中,可以使用haslayer()函数来判断是否具有某一个协议,例如,判断一个数据包是否使用了TCP,就可以使用haslayer(TCP)来判断,也可以使用getlayer(TCP),来读取某一个字段的内容,这里需要判断回应数据包是否为“SYN+ACK”类型,代码如下:

resp.getlayer(TCP).flags == 0x12 //0x12就是“SYN+ACK”

如果这个结果为真,表示目标接受我们的TCP请求,需要继续发送一个ACK数据包过去,完成三次握手。

IP(dst=dst_ip)/TCP(spor=src_port,dport=dst_port,flags=”AR”)

第三种:如果resp.getlayer(TCP).flags的结果不是0X12,而是0x14(表示RST)那么表示端口是关闭的。

使用如下的语句判断数据包是不是RST类型。

resp.getlayer(TCP).flags == 0x14 //0x14就是“RST”

按照上面讲的这些思路

设计一个基于TCP全开的完整端口扫描程序

import sys

from scapy.all import *

if len(sys.argv) != 3:

print('Usage:PortScan <IP>\n eg:PortScan 192.168.65.1 80')

sys.exit(1)

dst_ip = sys.argv[1]

src_port = RandShort()

dst_port=int (sys.argv[2])

packet = IP(dst = dst_ip)/TCP(sport=src_port,dport=dst_port,flags="S")

resp = sr1(packet,timeout = 5)

if(str(type(resp))=="<type 'noneType'>"):

print "The port %s is Closed" %(dst_port)

elif (resp.haslayer(TCP)):

if(resp.getlayer(TCP).flags == 0x12):

send_rst = sr(IP(dst = dst_ip)/TCP(sport=src_port,dport=dst_port,flags="AR"),timeout = 10)

print "The port %s is open" %(dst_port)

elif(resp.getlayer(TCP).flags == 0x14):

print "The port %s is Closed" %(dst_port)

代码执行结果如下。

代码中的RandShort函数功能是一个随机生成端口

基于TCP半开的端口扫描技术

TCP半开端口扫描的原理

全开扫描的话,可能会被主机的日志记录下来,而且最主要的是TCP连接三次握手中的最后一次是没用的,在目标返回了一个SYN+ACK类型的包,已经达到了探测的目标,可以考虑去除这一步。

于是一种基于TCP半开的端口扫描产生了,这种扫描的思想很简单。如果目标端口时开放的,那么在街道主机端口发出的SYN请求之后,就会返回一个SYN+ACK的回应,表示愿意接受这次连接的请求,然后主机端口不再回应一个ACK而是发送一个RST表示中断这个连接。这样实际上并没有建立好完成的TCP连接,称之为半开扫描。过程如图所示:

不过这个端口如果是关闭的话,扫描过程如图:

在这次半开扫描实例中,还要考虑一种不确定的状态,我们发出去的包很容易被过滤掉,过滤开能来自对方的而防火墙设备,路由器规则,防火墙等。这些端口几乎不提示任何信息,偶尔也会响应ICMP的错误信息,过程如图:

这样就将收到没有回应数据包的端口归于“filtered”状态,另外,考虑收到ICMP错误消息的情形,这种情况下,也要讲目标端口归于“filtered”状态,当TCP连接的是数据包被屏蔽时,一般返回如下的几种ICMP的错误信息

类型(type) 代码(code) 意义

3 1 主机不可达

3 2 协议不可达

3 3 端口不可达

3 9 目标网络被强制禁止

3 10 目的之际被强制禁止

3 13 由于过滤,通信被强制禁止

如果收到这几种类型的数据包,也将目标端口的状态归于“filtered”所以在写代码时候,考虑如下两种情况:

if(str(type(stealth_scab_resp)) == “<type ‘NoneType’>”)

这种情况表示没有收到任何回应包。

if(int(resp.getlayer(ICMP).type) == 3 and int(resp.getlayer(ICMP).code) in [1,2,3,9,10,13]):

这种情况表示收到的ICMP类型的数据包。

设计一个基于TCP半开的完整端口扫描程序

完整代码如下:

import sys

from scapy.all import *

if len(sys.argv) != 3:

print('Usage:PortScan <IP>\n eg:PortScan 192.168.65.1 80')

sys.exit(1)

dst_ip = sys.argv[1]

src_port = RandShort()

dst_port=int (sys.argv[2])

packet = IP(dst = dst_ip)/TCP(sport=src_port,dport=dst_port,flags="S")

resp = sr1(packet,timeout = 5)

if(str(type(resp))=="<type 'NoneType'>"):

print "The port %s is Filtered" %(dst_port)

elif (resp.haslayer(TCP)):

if(resp.getlayer(TCP).flags == 0x12):

send_rst = sr(IP(dst = dst_ip)/TCP(sport=src_port,dport=dst_port,flags="R"),timeout = 10)

print "The port %s is open" %(dst_port)

elif(resp.getlayer(TCP).flags == 0x14):

print "The port %s is Closed" %(dst_port)

elif(resp.haslayer(ICMP)):

if(int(resp.getlayer(ICMP).type) == 3 and int(resp.getlayer(ICMP).code) in [1,2,3,9,10,13]):

print "The port %s is Filtered" %(dst_port)

另外也可以用nmap库来进行TCP扫描,Nmap中默认的就是半开扫描,所以连参数都不用加,其代码如下:

import sys

import nmap

if len(sys.argv) != 3:

print('Usage:PortScan <IP>\n eg:PortScan 192.168.65.1 80')

sys.exit(1)

target = sys.argv[1]

port = sys.argv[2]

nm = nmap.PortScanner()

nm.scan(target,port)

for host in nm.all_hosts():

print('-------------------')

print('Host: {0} ({1})'.format(host,nm[host].hostnmae()))

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}\tstate : {1}'.format(port,nm[host][proto][port]))

这个程序本身简单,但是nmap的扫描结果格式很复杂,在服务扫描中会介绍。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。