扫描器之目标端口扫描与系统指纹分析
一、实验介绍
1.1 实验内容
利用python的socket模块连接端口-俗称端口扫描,通过对应的端口返回出对应的端口服务。
1.2 实验知识点
- Socket
- 对应端口对应服务
- 多线程的操作
- 扫描器中的使用
1.3 实验环境
- Python2.7
- Xfce终端
- Sublime
1.4 适合人群
本课程难度为一般,属于初级级别课程,适合具有Python基础的用户,熟悉python基础知识加深巩固。
1.5 代码获取
你可以通过下面命令将代码下载到实验楼环境中,作为参照对比进行学习。
$ wget http://labfile.oss.aliyuncs.com/courses/761/shiyanlouscan6.zip
$ unzip shiyanlouscan6.zip
二、实验原理
在渗透测试的初步阶段通常我们都需要对攻击目标进行信息搜集,而端口扫描就是信息搜集中至关重要的一个步骤。通过端口扫描我们可以了解到目标主机都开放了哪些服务,甚至能根据服务猜测可能存在某些漏洞。
TCP端口扫描一般分为以下几种类型:
- TCP connect扫描:也称为全连接扫描,这种方式直接连接到目标端口,完成了TCP三次握手的过程,这种方式扫描结果比较准确,但速度比较慢而且可轻易被目标系统检测到。
- TCP SYN扫描:也称为半开放扫描,这种方式将发送一个SYN包,启动一个TCP会话,并等待目标响应数据包。如果收到的是一个RST包,则表明端口是关闭的,而如果收到的是一个SYN/ACK包,则表示相应的端口是打开的。
- Tcp FIN扫描:这种方式发送一个表示拆除一个活动的TCP连接的FIN包,让对方关闭连接。如果收到了一个RST包,则表明相应的端口是关闭的。
- TCP XMAS扫描:这种方式通过发送PSH、FIN、URG、和TCP标志位被设为1的数据包。如果收到了一个RST包,则表明相应的端口是关闭的。
三、实验步骤
3.1 简单的扫描
引入skcket模块中的connect,可以连接一个指定端口。
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)
3.2 对应端口服务
一般查找对应指纹的方式是先连接到目标端口,然后发送一个指令,根据返回的数据得到对应的指纹,这个方法比较准确但要制作起来非常麻烦,要一个个测试每个端口对应的服务。
这里我提供一个比较简单但容错率比较低的方法,就是每个端口对应一个服务,如果扫描到这个端口,那么端口对应的服务也是这个。对于一般的网站来说,网站管理员一般也不会管理这些端口,不会特意修改,所以还是比较有用的,这里收集了端口服务指纹如下:
PORT = {80:"web",8080:"web",3311:"kangle",3312:"kangle",3389:"mstsc",4440:"rundeck",5672:"rabbitMQ",5900:"vnc",6082:"varnish",7001:"weblogic",8161:"activeMQ",8649:"ganglia",9000:"fastcgi",9090:"ibm",9200:"elasticsearch",9300:"elasticsearch",9999:"amg",10050:"zabbix",11211:"memcache",27017:"mongodb",28017:"mondodb",3777:"dahua jiankong",50000:"sap netweaver",50060:"hadoop",50070:"hadoop",21:"ftp",22:"ssh",23:"telnet",25:"smtp",53:"dns",123:"ntp",161:"snmp",8161:"snmp",162:"snmp",389:"ldap",443:"ssl",512:"rlogin",513:"rlogin",873:"rsync",1433:"mssql",1080:"socks",1521:"oracle",1900:"bes",2049:"nfs",2601:"zebra",2604:"zebra",2082:"cpanle",2083:"cpanle",3128:"squid",3312:"squid",3306:"mysql",4899:"radmin",8834:'nessus',4848:'glashfish'}
3.3 代码编写
在 /lib/core
中 编写 PortScan.py
整个代码如下:
#!/usr/bin/env python
# __author__= 'w8ay'
import socket
import threading
import Queue
class PortScan:
def __init__(self,ip="localhotst",threadNum = 5):
self.PORT = {80:"web",8080:"web",3311:"kangle",3312:"kangle",3389:"mstsc",4440:"rundeck",5672:"rabbitMQ",5900:"vnc",6082:"varnish",7001:"weblogic",8161:"activeMQ",8649:"ganglia",9000:"fastcgi",9090:"ibm",9200:"elasticsearch",9300:"elasticsearch",9999:"amg",10050:"zabbix",11211:"memcache",27017:"mongodb",28017:"mondodb",3777:"dahua jiankong",50000:"sap netweaver",50060:"hadoop",50070:"hadoop",21:"ftp",22:"ssh",23:"telnet",25:"smtp",53:"dns",123:"ntp",161:"snmp",8161:"snmp",162:"snmp",389:"ldap",443:"ssl",512:"rlogin",513:"rlogin",873:"rsync",1433:"mssql",1080:"socks",1521:"oracle",1900:"bes",2049:"nfs",2601:"zebra",2604:"zebra",2082:"cpanle",2083:"cpanle",3128:"squid",3312:"squid",3306:"mysql",4899:"radmin",8834:'nessus',4848:'glashfish'}
self.threadNum = threadNum
self.q = Queue.Queue()
self.ip = ip
for port in self.PORT.keys():
self.q.put(port)
def _th_scan(self):
while not self.q.empty():
port = self.q.get()
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.settimeout(1)
try:
s.connect((self.ip, port))
print "%s:%s OPEN [%s]"%(self.ip,port,self.PORT[port])
except:
print "%s:%s Close"%(self.ip,port)
finally:
s.close()
def work(self):
threads = []
for i in range(self.threadNum):
t = threading.Thread(target=self._th_scan())
threads.append(t)
t.start()
for t in threads:
t.join()
print('[*] The scan is complete!')
在具体实现过程中,首先用队列压入所有要检测的端口,
def __init__(self,ip="localhotst",threadNum = 5):
self.PORT = {80:"web",8080:"web",3311:"kangle",3312:"kangle",3389:"mstsc",4440:"rundeck",5672:"rabbitMQ",5900:"vnc",6082:"varnish",7001:"weblogic",8161:"activeMQ",8649:"ganglia",9000:"fastcgi",9090:"ibm",9200:"elasticsearch",9300:"elasticsearch",9999:"amg",10050:"zabbix",11211:"memcache",27017:"mongodb",28017:"mondodb",3777:"dahua jiankong",50000:"sap netweaver",50060:"hadoop",50070:"hadoop",21:"ftp",22:"ssh",23:"telnet",25:"smtp",53:"dns",123:"ntp",161:"snmp",8161:"snmp",162:"snmp",389:"ldap",443:"ssl",512:"rlogin",513:"rlogin",873:"rsync",1433:"mssql",1080:"socks",1521:"oracle",1900:"bes",2049:"nfs",2601:"zebra",2604:"zebra",2082:"cpanle",2083:"cpanle",3128:"squid",3312:"squid",3306:"mysql",4899:"radmin",8834:'nessus',4848:'glashfish'}
self.threadNum = threadNum
self.q = Queue.Queue()
self.ip = ip
for port in self.PORT.keys():
self.q.put(port)
创建一个线程函数,每个线程调用这个函数,这个函数的功能就是取出队列的端口,然后扫描。
def _th_scan(self):
while not self.q.empty():
port = self.q.get()
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.settimeout(1)
try:
s.connect((self.ip, port))
print "%s:%s OPEN [%s]"%(self.ip,port,self.PORT[port])
except:
print "%s:%s Close"%(self.ip,port)
finally:
s.close()
创建工作函数来调用线程:
def work(self):
threads = []
for i in range(self.threadNum):
t = threading.Thread(target=self._th_scan())
threads.append(t)
t.start()
for t in threads:
t.join()
print('[*] The scan is complete!')
进行测试:
检测实验楼开放的端口情况:
3.4 扫描需要的端口扫描器
上面代码保存到lib/core/PortScan.py
文件中,上面代码只能检测单个IP的端口开放情况,但是在扫描器中我们输出的域名,所以我们还需要写一个函数将域名对应到IP上。
3.5 域名->IP
首先我们需要用一个python内置的urlparse模块来解析url。
urlparse的简单用法:
我们需要得到ParseResult中netloc的值即可。
然后用一个 socket.gethostbyname 函数就可以获取到域名的ip地址了。
还是一张图解释用法:
考虑到这个可以写成公共函数,我们就写到 lib/core/common.py
中。
在 common.py
中先导入一些我们需要用的库
import urlparse
import socket
命名这个函数:
def gethostbyname(url):
domain = urlparse.urlparse(url)
# domain.netloc
if domain.netloc is None:
return None
ip = socket.gethostbyname(domain.netloc)
return ip
3.6 集成到扫描器中
修改下w8ay.py 这个主入口文件。
#!/usr/bin/env python
#-*- coding:utf-8 -*-
'''
Name:w8ayScan
Author:w8ay
Copyright (c) 2017
'''
import sys
from lib.core.Spider import SpiderMain
from lib.core import webcms, common, PortScan
reload(sys)
sys.setdefaultencoding('utf-8')
def main():
root = "https://shiyanlou.com"
threadNum = 10
ip = common.gethostbyname(root)
print "IP:",ip
print "Start Port Scan:"
pp = PortScan.PortScan(ip)
pp.work()
#webcms
ww = webcms.webcms(root,threadNum)
ww.run()
#spider
w8 = SpiderMain(root,threadNum)
w8.craw()
if __name__ == '__main__':
main()
加上我们的端口扫描模块。
最后的结果:
四、实验总结
现在。我们的扫描器运行流程是:
- 域名->转换ip->端口扫描
- CMS识别
- 爬虫信息收集->调用插件
已经有了基本扫描器的雏形了。