本文介绍使用Python来实现渗透测试过程中的端口扫描。
接触过网络技术的同学大概都知道端口是什么东西,没有接触过的同学,经过下面的简单详情应该也可以明白端口是个什么东西。
在网络上我们会用到各种各样的服务(当然不是各种各样的网站,网站所提供的多是Web服务),比方浏览网站,发送邮件,用FTP下载某些资源,用SSH或者Telnet连接远程服务器等。这些服务有可可以都是由同一个服务器提供的。
同一个服务器上提供那么多服务,怎样对他们进行区分呢?端口就是使用来对他们进行区分和唯一标识的,每一个服务都用不同的端口,就像一栋楼里面的不同房间一样。
我们常见的网站Web服务默认用的是80端口,使用来上传和下载文件的FTP用的是21端口等等。
我们通过域名或者IP地址找到对应的服务器,而后再通过端口号,找到对应的服务。
有需要更加详细的详情的同学,能查看各种百科:https://baike.baidu.com/item/%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF%E5%8F%A3/718781?fr=aladdin
我们知道服务器的端口之上运行着对应的服务,而服务都有其版本。我们对服务器进行端口扫描,有两个目的:
这两个目的都是为了缩小行动的范围,提交行动的效率和精确性。例如我们知道了某个主机开启了80端口,那么其就很有可可以提供了Web服务,我们即可以进一步通过其Web服务用的语言(比方PHP)和框架(比方WordPress)以及框架的版本(比方4.8.2)去寻觅相应的漏洞。
又比方我们经常用SSH来远程登录服务器,其默认运行于22端口之上,假如我们扫描到了服务器开启了这个端口,那么服务器很有可可以开启了远程连接的功可以,假如我们获取ssh的banner得到其服务版本正好是一个存在安全漏洞的版本,那么就有了一个新的测试攻击点。
2.2、Python实现
那么我们如何用Python进行端口的识别和扫描呢?
在Python中,有一个内置板块——socket提供了网络socket的操作,其中包含了如下函数来支持socket连接的具体功可以实现:
gethostbyname() -- 映射主机名到对应的IP地址上
gethostbyaddr() -- 映射主机名或者IP地址到DNS信息上
getservbyname() -- 映射服务名称和端口名称到端口号上
getprotobyname() -- 映射协议名称到一个数字上
ntohs(), ntohl() -- 将16, 32位整数从网络转换为主机字节顺序
htons(), htonl() -- 将16, 32位整数从主机转换为网络字节顺序
inet_aton() -- 将IP地址从字符串转换为32位字节数据格式
inet_ntoa() -- 将IP地址从32位字节转换为字符串
socket.getdefaulttimeout() -- 获取默认连接超时值
socket.setdefaulttimeout() -- 设置默认连接超时值
create_connection() -- 通过源地址和设置连接超时创立一个链接
我们能通过这个板块的socket()函数创立一个socket对象来连接服务器的指定端口,比方下列代码所示:
# 引入socket板块
import socket
# 实例化一个socket对象
s = socket.socket()
# 与远程服务器的指定端口建立socket连接
s.connect((huabandata.com,22))
# 关闭连接
s.close()
上述代码我们就通过socket板块的socket()函数建立了对huabandata.com这个域名的22端口的socket连接,而后进行了连接的关闭。
当然,连接成功是不可可以的,这样做一辈子都不可可以连接成功。运行这段代码甚至连输出的信息都不会有:
如何得到socket连接的输出信息呢?socket对象中的一个方法——recv()或者许能帮到我们:
它的作使用是从socket连接中返回指定大小的字节,我们继续测试一下这个方法:
# 引入socket板块
import socket
# 实例化一个socket对象
s = socket.socket()
# 与远程服务器的指定端口建立socket连接
s.connect((192.168.223.152,22))
# 打印输出从socket连接中返回的1024个字节
print(s.recv(1024))
# 关闭连接
s.close()
在此,我们用了著名的渗透测试框架Metasploit提供的靶机虚拟机Metasploitable2来作为目标主机,这是一个容易受到攻击的Linux虚拟机。这个虚拟机能使用来进行安全培训,测试安全工具,并练习常使用的渗透测试技术。
目标主机的IP地址有需要的同学在sourceforge进行下载,下载链接为:https://sourceforge.net/projects/metasploitable/
运行代码,我们得到了socket返回的前1024个字节(一般是服务信息的banner):
通过这个返回的banner信息,我们能知道这个服务器的22端口是开放的,而且其服务版本是ubuntu上的openssh 4.7。
能发现,借助于recv()方法,我们能获取到端口服务的最基本信息,但是假如对应的端口没有开启或者者有其余的限制,那么即可可以会报错。比方下面这样:
# 引入socket板块
import socket
# 实例化一个socket对象
s = socket.socket()
# 与远程服务器的指定端口建立socket连接
s.connect((192.168.223.152,88))
# 打印输出从socket连接中返回的1024个字节
print(s.recv(1024))
# 关闭连接
s.close()
我们连接目标主机的23端口,其返回了一个XXX异常错误,如下动图所示:
socket连接88端口报错综上所述的情况,我们利使用socket的几个方法略微组合一下,即可以创立一个使用于端口扫描的脚本。
1.首先引入socket板块:
import socket
2.接着实例化一个socket对象:
s = socket.socket()
3.设置socket连接超时时间为3秒
s.settimeout(3)
4.接收键盘输入需扫描的端口号:
port = input("请输入端口号:")
5.连接并打印返回的字节:
try:
s.connect(("192.168.223.152",int(port)))
print (s.recv(1024))
s.close()
except Exception as e:
print (">>>扫描错误:",e)
最后完整的代码如下所示:
import socket
s = socket.socket()
s.settimeout(3)
port = input("请输入端口号:")
try:
s.connect((192.168.223.152,int(port)))
print (s.recv(1024))
s.close()
except Exception as e:
print (">>>扫描错误:",e)
下面,我们来测试一下这个端口扫描器:
端口扫描脚本效果,这样,一个简单的主机端口扫描器就完成了。