• 『Python』 多线程 端口扫描器


      0x 00 Before Coding

      当端口打开时,向端口发送 TCP SYN 请求,会返回一个 ACK 响应:

      

      当端口关闭,返回的是 RST 响应:

      

      0x 01 Coding 

      可以用 socket 编写一个小脚本来测试主机端口的开启情况,基本代码如下:

      

     1 # coding: utf-8
     2 
     3 import socket
     4 from datetime import datetime
     5 
     6 # Set time-out to get the scanning fast
     7 socket.setdefaulttimeout(0.5)
     8 
     9 # Ask for input
    10 remote_server = raw_input("Enter a remote host to scan:")
    11 remote_server_ip = socket.gethostbyname(remote_server)
    12 
    13 # Print a nice banner with info on which host we are about to scan
    14 print '-' * 60
    15 print 'Please wait, scanning remote host ', remote_server_ip
    16 print '-' * 60
    17 
    18 # Check what time the scan started
    19 t1 = datetime.now()
    20 
    21 # Using the range function to specify ports(1 - 1024)
    22 # We also put in some error handling for catching errors
    23 try:
    24     for port in range(1,1025):
    25         sock = socket.socket(2,1) # 2:socket.AF_INET 1:socket.SOCK_STREAM
    26         res = sock.connect_ex((remote_server_ip,port))
    27         if res == 0:
    28             print 'Port {}: OPEN'.format(port)
    29         sock.close()
    30 
    31 except socket.gaierror:
    32     print 'Hostname could not be resolved.Exiting'
    33 
    34 except socket.error:
    35     print "Could't connect to the server"
    36 
    37 # Check the time now
    38 t2 = datetime.now()
    39 
    40 # Calculates the difference of time
    41 total = t2 - t1
    42 
    43 # Print the info to screen
    44 print 'Scanning Completed in: ', total

      参考:http://www.pythonforbeginners.com/code-snippets-source-code/port-scanner-in-python/

      程序测试结果如下:

      

      看出来 在 socket 的超时时间设置为0.5的前提下 依然需要花费 8分27秒才能够把周知端口号扫完,有没有其他方式加快扫描速度?答案是有的。

      //////////////////// ******************** 该部分可以略过,一个小坑 ************************ ////////////////////

      打开 抓到的数据包列表,发现 timeout 包都会发送2个“伪重传”,发送这两个一般没什么用的数据包会占用 CPU的处理时间,

      所以在想能不能不让程序发这两个包来提高效率??

      自己分析连续两个端口的时间间隔就会发现:间隔是0.5s(由 39号、46号、53号数据包分析得出),这恰好是在程序中设置的超时时间,

      也就是说超时重传的包并不会占用专门的时间,所以这种想法就被干掉了。

     

      这样的话,1个端口0.5的超时等待,扫描一个主机的 1- 1024 号端口所用时间是可以大致估算下的:

      1024 * 0.5 / 60 = 8.53 分钟左右。和上面程序实际扫描的时间(8分27秒)相符合。

      //////////////////// ******************** 坑结束  ************************ ////////////////////

      0x 02 Better Coding  

      所以对于这种时间主要花费在 socket 连接( 非 CPU 计算密集型 )的程序 可以使用 多线程来提升效率,

      这里选择使用内建的库 multiprocessing.dummy 来实现多线程扫描:

    # coding: utf-8
    '''
      多线程 Socket TCP 端口扫描器 by: EvilCLAY
    ''' import socket from datetime import datetime from multiprocessing.dummy import Pool as ThreadPool remote_server = raw_input("Enter a remote host to scan:") remote_server_ip = socket.gethostbyname(remote_server) ports = [] print '-' * 60 print 'Please wait, scanning remote host ', remote_server_ip print '-' * 60 socket.setdefaulttimeout(0.5) def scan_port(port): try: s = socket.socket(2,1) res = s.connect_ex((remote_server_ip,port)) if res == 0: # 如果端口开启 发送 hello 获取banner print 'Port {}: OPEN'.format(port) s.close() except Exception,e: print str(e.message) for i in range(1,1025): ports.append(i) # Check what time the scan started t1 = datetime.now() pool = ThreadPool(processes = 8) results = pool.map(scan_port,ports) pool.close() pool.join() print 'Multiprocess Scanning Completed in ', datetime.now() - t1

      扫描的结果如下:

      

      可以发现 8 个线程并行发起请求,效率有很大的提升。

      在被扫描主机未安装连接限制软件的前提下,测试了开启不同线程扫描所花费的时间 :

      16 个线程 使用 32 秒扫完;
      32个线程,使用 16 秒扫完;
      64个线程,使用 8 秒扫完;
      128个线程,使用 4 秒扫完;
      256个线程,使用 2 秒扫完;
      512个线程,使用 1.50 秒扫完;
      1024个线程,使用 1.25 秒扫完;





      获取 Banner
      把 函数修改成如下 即可:
    def scan_port(port):
        try:
            s = socket.socket(2,1)
            res = s.connect_ex((remote_server_ip,port))
            if res == 0: # 如果端口开启 发送 hello 获取banner
    
                try:
                    s.send('hello')
                    banner = s.recv(1024)
    
    
                except Exception,e:
                    print 'Port {}: OPEN'.format(port)
                    print str(e.message)
                else:
                    print 'Port {}: OPEN'.format(port)
                    print 'Banner {}'.format(banner)
    
            s.close()
        except Exception,e:
            print str(e.message)
    

      晚上研究下 Zmap 与 ZGrab 分析下  这两款神器牛在什么地方 ~~


  • 相关阅读:
    写代码时减少bug的八种方式
    ObjectiveC中对Url的参数进行编码
    iPhone中预览文档的三种方式
    GUID和INT两种数据类型做主键的比较
    通过FxCop来验证.NET编码规范
    一位程序员的一个LBS应用的想法
    iPhone中XML处理以及网络上的图片显示
    iOS开发之iPhone通过get和post方式请求asp.net webservice
    iOS开发之将XML转换成树
    objectivec内存管理基础
  • 原文地址:https://www.cnblogs.com/anka9080/p/socket_ports_scanner.html
Copyright © 2020-2023  润新知