connect全连接扫描,基于socket套接字的connect方法,它的参数是一个元组(ip, port),此扫描试图与每一个TCP端口进行“三次握手”通信。如果能够成功建立接连,则证明端口开发,否则为关闭。准确度很高。缺点:最容易被防火墙和IDS检测到,并且在目标主机的日志中会记录大量的连接请求以及错误信息。优点:另一优点是扫描速度快。如果对每个目标端口以线性的方式,使用单独的connect()调用,可以通过同时打开多个套接字,从而加速扫描。
SYN半连接扫描,扫描IP段的全部端口部分的实现,基于scapy构造SYN数据包向目标主机的一个端口发送连接请求,当我们收到SYN/ACK包后,不发送的ACK应答而是发送RST包请求断开连接。这样,三次握手就没有完成,无法建立正常的TCP连接,因此,这次扫描就不会被记录到系统日志中,但是可能会在防火墙上留下痕迹。
1、Client发送SYN
2、Server端发送SYN/ACK
3、Client发送RST断开(只需要前两步就可以判断端口开放)
1、Client发送SYN
2、Server端回复RST(表示端口关闭)
输入:
是一个ip的list文件(按行存储的都可以),例如下面这样:
104.168.0.0/16,pcapname
104.28.0.0/16,pcapname
134.29.0.0/16,pcapname
21.61.127.231,pcapname_port
221.17.0.0/16,pcapname
23.25.36.58,pcapname_port
输出:
对应的IP和开放的PORT及其pcapname和扫描时间插入mysql,日志输出
# 单个IP全端口扫描
import time
import socket
import threading
from scapy.all import *
class SingelIP_Scan:
def connScan(self, tgtHost, tgtPort, name):
try:
# SYN扫描
syn = IP(dst=tgtHost)/TCP(dport=tgtPort, flags=2)
result_raw = sr(syn, iface='enp6s0f0', timeout=1, verbose=False) # Linux下少了iface参数,需要加上
result_list = result_raw[0].res
for i in range(len(result_list)):
if result_list[i][1].haslayer(TCP):
TCP_fields = result_list[i][1].getlayer(TCP).fields
if TCP_fields['flags'] == 18:
port = TCP_fields['sport']
# print('[+]', port, ' : is open', name)
n = News(tgtHost, port, name)
n.insert()
logger.warning('from: ' + name + ' insert [+] ' + tgtHost + ' [+] ' + str(port) + ' : is open')
except:
# print("[-]%d/tcp close" % tgtPort)
pass
def portScan(self, tgtHost, name):
try:
tgtIP = socket.gethostbyname(tgtHost)
except:
# print("[-]cannot connect %s" % tgtIP)
logger.warning(' [-] ' + tgtIP + ' can not connect')
return
# print("\n[+]scan results for:" + tgtIP)
if '_' in name:
result = name.split('_')
name = result[0]
if result[1].isdigit():
port = int(result[1])
self.connScan(tgtHost, port, name)
else:
for port in range(0, 65535):
time.sleep(1)
print("scanning port:" + str(port))
t2 = threading.Thread(target=self.connScan, args=(tgtHost, port, name))
# t.daemon = True
t2.start()
# self.connScan(tgtHost,int(port), name)
else:
for port in range(0, 65535):
time.sleep(1)
# print("scanning port:" + str(port))
t3 = threading.Thread(target=self.connScan, args=(tgtHost, port, name))
# t.daemon = True
t3.start()
import logging
from scapy.all import *
from random import randint
import threading
import time
from config import *
logging.getLogger('scapy.runtime').setLevel(logging.ERROR)
class SegmentIP_Scan:
def ping_one(self, host):
ip_id = randint(1, 65535)
icmp_id = randint(1, 65535)
icmp_seq = randint(1, 65535)
packet = IP(dst=host, ttl=64, id=ip_id)/ICMP(id=icmp_id, seq=icmp_seq)/b'hello'
ping = sr1(packet, iface='enp6s0f0', timeout=2, verbose=False) # Linux下少了iface参数,指定网卡
if ping:
return 0
else:
return -1
def loop_addrs(self, addrs, pcapname):
for addr in addrs:
if self.ping_one(addr) == -1:
# 说明对方关机,或者没有这个地址,设置了ICMP数据包过滤
# print(addr, ': 不可达') # 不能有中文
logger.warning(' [-] ' + addr + ' can not connect')
else:
t4 = threading.Thread(target=self.syn_scan, args=(addr, pcapname)) # , 100, 500
# t.daemon = True # 全开守护线程快是快,但是开100个线程就占用大概3G的运存
t4.start()
def syn_scan(self, hostname, pcapname): # , lport, hport
# print('scan: ', hostname, pcapname) # , str(lport), '-', str(hport)
if '_' in pcapname:
result = pcapname.split('_')
pcapname = result[0]
if result[1].isdigit():
port = int(result[1])
syn = IP(dst=hostname)/TCP(dport=port, flags=2)
result_raw = sr(syn, iface='enp6s0f0', timeout=1, verbose=False) # iface参数
result_list = result_raw[0].res
for i in range(len(result_list)):
if result_list[i][1].haslayer(TCP):
TCP_fields = result_list[i][1].getlayer(TCP).fields
if TCP_fields['flags'] == 18:
port = TCP_fields['sport']
# print('[+]', port, ' : is open')
n = News(hostname, port, pcapname)
n.insert()
logger.warning('from: ' + pcapname + ' insert [+] ' + hostname + ' [+] ' + str(port) + ' : is open')
else:
for port in range(0, 65535):
time.sleep(1)
syn = IP(dst=hostname)/TCP(dport=port, flags=2)
result_raw = sr(syn, iface='enp6s0f0', timeout=1, verbose=False)
result_list = result_raw[0].res
for i in range(len(result_list)):
if result_list[i][1].haslayer(TCP):
TCP_fields = result_list[i][1].getlayer(TCP).fields
if TCP_fields['flags'] == 18:
port = TCP_fields['sport']
# print('[+]', port, ' : is open')
n = News(hostname, port, pcapname)
n.insert()
logger.warning('from: ' + pcapname + ' insert [+] ' + hostname + ' [+] ' + str(port) + ' : is open')
else:
for port in range(0, 65535):
time.sleep(1)
syn = IP(dst=hostname)/TCP(dport=port, flags=2)
result_raw = sr(syn, iface='enp6s0f0', timeout=1, verbose=False) # iface参数
result_list = result_raw[0].res
for i in range(len(result_list)):
if result_list[i][1].haslayer(TCP):
TCP_fields = result_list[i][1].getlayer(TCP).fields
if TCP_fields['flags'] == 18:
port = TCP_fields['sport']
# print('[+]', port, ' : is open')
n = News(hostname, port, pcapname)
n.insert()
logger.warning('from: ' + pcapname + ' insert [+] ' + hostname + ' [+] ' + str(port) + ' : is open')
from ip_List_All import *
from ip_scan_all import *
from config import *
import re
import threading
def ip_match(line):
p = re.compile(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(\/{0,1}\d{0,3})(.\w*\_{0,1}\w*)')
s = p.match(line)
name = s.group(3)[1:]
result = []
if s:
if s.group(2) == '/16': # and '_' not in s.group(3)[1:]:
q = re.compile(r'(\d{1,3}\.\d{1,3}\.)')
a = q.match(s.group(1))
h = a.group(1)
ips = []
for i in range(256):
ip1 = h + str(i)
for j in range(256):
ip2 = ip1 + '.' + str(j)
ips.append(ip2)
result.append(2)
result.append(ips)
result.append(name)
# print(result)
return result
elif s.group(2) == '/24': # and '_' not in s.group(3)[1:]:
q = re.compile(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.)')
a = q.match(s.group(1))
h = a.group(1)
ips = []
for i in range(256):
ip1 = h + str(i)
ips.append(ip1)
result.append(2)
result.append(ips)
result.append(name)
# print(result)
return result
elif '/' not in s.group(2): # and '_' not in s.group(3)[1:]:
result.append(4)
result.append(s.group(1))
result.append(name)
# print(result)
return result
def read_ip_list(filename):
# 返回值为2: 走ip_list全端口扫描或指定端口
# 返回值为4: 走单个ip全端口扫描或指定端口
with open(filename, 'r') as f:
lines = f.readlines()
for line in lines:
a = ip_match(line)
if a[0] == 2:
scan = SegmentIP_Scan()
# scan.loop_addrs(a[1], a[2])
t = threading.Thread(target=scan.loop_addrs, args=(a[1], a[2]))
t.start()
elif a[0] == 4:
scan = SingelIP_Scan()
# scan.portScan(a[1], a[2])
t1 = threading.Thread(target=scan.portScan, args=(a[1], a[2]))
t1.start()
if __name__ == '__main__':
try:
read_ip_list('ip.list')
except Exception as e:
print(e)
finally:
logger.warning('scaner finished!')
# 注意在Linux下跑的时候需要sudo权限,
# 使用scapy的sr发包的时候需要添加上,选用的网卡信息 iface参数
import logging
from contextlib import closing
import datetime
import pymysql as Mdb
logger = logging.getLogger("scan_port")
formatter = logging.Formatter('%(name)s %(asctime)s %(levelname)-5s %(lineno)d: %(message)s')
file_handler = logging.FileHandler("log/scan_port.log")
file_handler.setFormatter(formatter)
file_handler.setLevel(logging.WARNING)
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
console_handler.setLevel(logging.DEBUG)
logger.addHandler(console_handler)
logger.addHandler(file_handler)
logger.setLevel(logging.INFO)
class News(object):
def __init__(self, scan_ip, open_port, pcapname):
self.__scan_ip = scan_ip
self.__open_port = open_port
self.__pcapname = pcapname
def insert(self):
with closing(Mdb.connect("127.0.0.1", "root", "password", "db01",charset="utf8")) as db:
with closing(db.cursor()) as cursor:
now_time = datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%dT%H:%M:%S")
cursor.execute("INSERT INTO tablename(`scan_ip`, `open_port`, `pcapname`, `updated_time`) VALUES (%s,%s,%s,%s)", \
(self.__scan_ip, self.__open_port, self.__pcapname, now_time))
db.commit()
BUG: 这个代码有个问题就是发送SYN给端口时对于防火墙返回SYN/ACK的时候无法判断是否可连接(防火墙对65535个端口都返回),可以完成握手但是,不能通信