使用Python扫描主机中的每个可能端口

Gre*_*der 5 python ip port tcp python-multithreading

我正在编写一个程序,需要扫描主机中的所有65535个端口,搜索那些打开的端口.这是我到目前为止,它的工作原理,但每次执行脚本时都会产生不同的结果,为什么会这样?

def check_open_port(host, port):
    s = socket.socket()
    s.settimeout(0.1)
    # the SO_REUSEADDR flag tells the kernel to reuse a local 
    # socket in TIME_WAIT state, without waiting for its natural
    # timeout to expire.
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    try:
        code = s.connect_ex((host, port))
        s.close()

        if code == 0:
            return True
        else:
            return False
    except socket.error:
        return False


def get_open_ports(host, max_port=65535):
    open_ports = []

    def worker(port):
        if check_open_port(host, port):
            open_ports.append(port)


    pool = ThreadPoolExecutor(max_workers=10000)
    [pool.submit(worker, port) for port in range(1, max_port + 1)]
    pool.shutdown(wait=True)

    return open_ports
Run Code Online (Sandbox Code Playgroud)

例如,在端口22,80和443打开的主机中,有时我得到此响应:

[22, 80]

有时我得到:

[22, 80, 443]

甚至:

[22]

具有更多开放端口的主机产生更多组合.

我玩过max_workers和玩过settimeout()价值观,但我无法让它运作良好.它唯一有效的时间是不使用线程,但显然需要很长时间才能完成,我需要使用它们.

我错过了什么吗?还有其他方法可以实现吗?

ffe*_*ast 7

这里有2个问题:

  1. 我错过了什么
  2. 还有其他方法可以实现吗?

我错过了什么

我认为值得在此检查错误代码:

if code == 0: 
    return True
else:
    return False
Run Code Online (Sandbox Code Playgroud)

鉴于你正试图运行一个池!10K线程可能会出现所有类型的错误 - 即达到某个系统/您的用户限制(检出ulimit -a),您可以将此类错误视为封闭端口而不另行通知.它可能解释您遇到的不稳定结果.

BTW在我的MacBook上结果是一致的(在VPS主机上查看我的实时服务器)

我也会选择更少数量的线程--10K是一种过度杀伤力.例如,以下是python 文档中建议的默认值:

在版本3.5中更改:如果max_workers为None或未给出,则默认为机器上的处理器数量,乘以5,假设ThreadPoolExecutor经常用于重叠I/O而不是CPU工作,并且工作者数量应该高于ProcessPoolExecutor的工作者数量

还有其他方法可以实现吗?

首先,没有必要使用threads/processes- 非阻塞套接字+ 像epoll这样的事件多路复用器已存在多年,所以你可以在没有额外线程/处理的情况下逃脱.

连接/关闭的方法也不是最理想的,因为您只需要检查端口是否打开 - 这里不需要全连接TCP连接.

在最简单的情况下,您只需发送一个SYN段并检查服务器将响应什么.

这是一篇使用scapy的十几种方法的文章

Scapy是一个功能强大的交互式数据包操作程序.它能够伪造或解码大量协议的数据包,通过线路发送,捕获它们,匹配请求和回复等等.它可以轻松处理大多数经典任务,如扫描,跟踪路由,探测,单元测试,攻击或网络发现(它可以取代hping,85%的nmap,arpspoof,arp-sk,arping,tcpdump,tethereal,p0f等).

这是方法描述之一(" TCP连接扫描 "):

客户端使用SYN标志和端口发送第一次握手,以连接到TCP数据包中的服务器.如果服务器使用RST而不是SYN-ACK进行响应,则在服务器上关闭该特定端口

还有一种方法(" TCP隐形扫描 "):

此技术类似于TCP连接扫描.客户端发送一个TCP数据包,其中设置了SYN标志和要连接的端口号.如果端口打开,则服务器使用TCP数据包内的SYN和ACK标志进行响应.但是这次客户端在TCP数据包中发送RST标志而不是RST + ACK,这是TCP连接扫描中的情况.此技术用于避免防火墙检测端口扫描

当然,如果只想玩套接字/线程,你的方法即使没有pcap/scapy也会很好


ama*_*anb 5

我在jupyter笔记本上尝试了你的代码,我总是得到相同的端口集:

get_open_ports('127.0.0.1')
Run Code Online (Sandbox Code Playgroud)

输出:

[133, 200, 144...60700]

是否有可能在特定时间打开不同数量的端口以供查询主机?

为了验证一小组端口,我减少max_port10000,每次仍然得到相同的端口集:

def get_open_ports(host, max_port=10000):
open_ports = []

def worker(port):
    if check_open_port(host, port):
        open_ports.append(port)

with ThreadPoolExecutor(max_workers=10000) as executor:
    [executor.submit(worker, port) for port in range(1, max_port + 1)]
    executor.shutdown(wait=True)
return open_ports

get_open_ports('127.0.0.1')
Run Code Online (Sandbox Code Playgroud)

输出: [150, 900, 1035, 7789]

注意:出于安全考虑,我更改了端口号.

编辑:

def get_open_ports(host, max_port=65535):
    open_ports = []

    def worker(port):
        if check_open_port(host, port):
            open_ports.append(port)

# We can use a with statement to ensure threads are cleaned up promptly
    with ThreadPoolExecutor(max_workers=100) as executor:
        print('main:starting')
        wait_for=[executor.submit(worker,port) for port in range(1, max_port + 1)]
        for f in as_completed(wait_for):
            print('main: result: {}'.format(f.result())) #check result on each thread execution

#         executor.shutdown(wait=True)  #not required when using the 'with' statement
    return len(open_ports)

test = get_open_ports('45.60.112.163') #hostname for www.indracompany.com

#max_workers not defined & max_port=10000
# len(test)     #test1: 148
# len(test)     #test 2: 79

#max_workers = 10000 & max_port=65535
# len(test)      #test1: 1
# len(test)      #test2:1
# len(test)      #test3:1

#max_workers = 20000 & max_port=65535

# len(test)  #test1: 14
# len(test)  #test2:1
# len(test)  #test3: 1
# len(test)  #test4:1

#max_workers not defined & max_port=65535 #quite time-consuming
# len(test)   #test1: 63
Run Code Online (Sandbox Code Playgroud)

编辑2:更可靠的解决方案

正如@Tarun所建议的那样,Python的python-nmap库在扫描主机方面做得更好.

以下解决方案给出了准确的结果,但是,随着端口发现范围的增加,我观察到了性能上的重大折衷.也许,线程可以合并到代码中以提高性能.我还导入了时间库以最终获得程序执行时间.在测试性能时,这可用于比较目的.

# The python-nmap library helps to programmatically manipulate scanned results of nmap to automate port scanning tasks. 
# To use this library you must have the Nmap software installed. This can be installed from https://nmap.org/download.html.
# Network Mapper (Nmap) is a free and open-source tool used for network discovery and security auditing. 
# It runs on all major computer operating systems, and official binary packages are available for Linux, Windows, and Mac OS X.
# For Windows 7 and later, you must also upgrade 'NCap' from https://nmap.org/npcap/ 
# For Windows, make sure nmap.exe is added to PATH.
# When you're ready, pip install python-nmap

import time
import nmap
nm = nmap.PortScanner() #initialize PortScanner object
host = '45.60.112.163'  #specify host
nm.scan(host, '1-100') #run the scan, specify host and range of ports to scan

#Optional steps for verification:

#Output: nmap -oX - -p 1-100 -sV 45.60.112.163
print(nm.command_line()) #command_line command to execute on nmap command prompt

#Output: {'tcp': {'method': 'syn', 'services': '1-100'}}
print(nm.scaninfo())   #nmap scan information

#Now we can scan all hosts
#From Official documentation at https://xael.org/pages/python-nmap-en.html
start_time = time.time()   #To get program execution time
for host in nm.all_hosts(): 
    print('----------------------------------------------------')
    print('Host : %s (%s)' % (host, nm[host].hostname()))
    print('State : %s' % nm[host].state())
    for proto in nm[host].all_protocols():
        print('----------')
        print('Protocol : %s' % proto)
        lport = nm[host][proto].keys()
        for key in sorted(lport):
            for port in lport:
                print ('port : %s\tstate : %s' % (port, nm[host][proto][port]['state']))
print('Execution time: %s seconds' % (time.time() - start_time))

    #Output:
    ----------------------------------------------------
    Host : 45.60.112.163 ()
    State : up
    ----------
    Protocol : tcp
    port : 25       state : open
    port : 51       state : open
    port : 53       state : open
    port : 80       state : open
    port : 81       state : open
    port : 85       state : open
    port : 91       state : open
    port : 25       state : open
    port : 51       state : open
    port : 53       state : open
    port : 80       state : open
    port : 81       state : open
    port : 85       state : open
    port : 91       state : open
    port : 25       state : open
    port : 51       state : open
    port : 53       state : open
    port : 80       state : open
    port : 81       state : open
    port : 85       state : open
    port : 91       state : open
    port : 25       state : open
    port : 51       state : open
    port : 53       state : open
    port : 80       state : open
    port : 81       state : open
    port : 85       state : open
    port : 91       state : open
    port : 25       state : open
    port : 51       state : open
    port : 53       state : open
    port : 80       state : open
    port : 81       state : open
    port : 85       state : open
    port : 91       state : open
    port : 25       state : open
    port : 51       state : open
    port : 53       state : open
    port : 80       state : open
    port : 81       state : open
    port : 85       state : open
    port : 91       state : open
    port : 25       state : open
    port : 51       state : open
    port : 53       state : open
    port : 80       state : open
    port : 81       state : open
    port : 85       state : open
    port : 91       state : open
    Execution time: 0.015624761581420898 seconds
Run Code Online (Sandbox Code Playgroud)

要将输出转换为csv,请使用:

print(nm.csv())
Run Code Online (Sandbox Code Playgroud)

经过这次调查,Nmap现已安装在我的计算机上.为了好玩,我还使用下面的命令在命令提示符上运行扫描.这次扫描的范围是"1-1000",耗时超过15分钟(我没有参加整个会议!).

在此输入图像描述