写在前面:之前在学校的时候自学过C,java,PHP(虽然都只学了个皮毛), 又到工作中学了Python, 现在一直靠Python混饭吃,目前也只写一下web后端逻辑和业余写一下小爬虫。一直以来对网络安全很感兴趣,最近在京东上花了62元,买了一本《Python绝技》这本书,接下来业余时间,我会按照书上的内容来走一遍,学习一下渗透知识。
本书全程都是用的Python2写的,但是我非常不习惯Python2,结合书上的案例我又去google这些名词,开局第一章是一些基本介绍然后就是Python的基础内容,直接跳过,然后就是第二章,讲了一个Unix破解口令的代码,看了一下大概思路,就是用枚举法字典暴力破解,感觉没啥技术含量,我也就没试。
今天我敲了一个基于Python3的TCP端口扫描器, 话不多说上代码.
#!/usr/bin/python3 # -*-coding:utf-8-*- # @Author: wg # @Time: 2018/03/04 20:22:18 import socket import re import threading import time lock = threading.Lock() threads = list() ports_list = list() def judge_hostname_or_ip(target_host): """判断输入的是域名还是IP地址""" result = re.match( r"^(\d|[1-9]\d|1\d\d|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.(\d|[1-9]\d|1\d\d|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\." "(\d|[1-9]\d|1\d\d|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.(\d|[1-9]\d|1\d\d|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$", target_host) if result: # print(result.group()) return result.group() else: try: socket.setdefaulttimeout(1) IP = socket.gethostbyname(target_host) return IP except Exception as e: print("请正确输入网址或者ip地址...", e) exit() def parse_port(ports): """把连接符-传输过来的值解析为对应的数字 端口范围1-65535""" if ports: try: res = re.match(r'(\d+)-(\d+)', ports) if res: if int(res.group(2)) > 65535: print("末尾端口输入有误!!....请新输入") exit() return range(int(res.group(1)), int(res.group(2))) except: print("端口解析错误.....请正确输入端口范围") exit() else: return [19, 21, 22, 23, 25, 31, 42, 53, 67, 69, 79, 80, 88, 99, 102, 110, 113, 119, 220, 443] def test_port(host, port): """测试端口是否开启""" try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((host, port)) lock.acquire() # 加线程锁 print("{}, {}端口打开".format(host, port)) ports_list.append(port) except: lock.acquire() finally: lock.release() s.close() def main(): ip = judge_hostname_or_ip(input("请输入域名或者IP:")) l = parse_port(input("请输入端口范围如: 1-1024 [不输入直接回车默认扫描常见端口]:")) t1 = time.time() # 每个套接字的最大超时时间 socket.setdefaulttimeout(3) # 开启线程来测试 for port in l: t = threading.Thread(target=test_port, args=(ip, port)) threads.append(t) # 添加到等待线程列表里面 t.start() for t in threads: t.join() # 等待线程全部执行完毕 t2 = time.time() print("总共耗时:", t2 - t1) print("IP:{}, 有{},共{}个端端口打开".format(ip, ports_list, len(ports_list))) if __name__ == '__main__': main()
其实原理很简单,就是很不同的端口进行TCP连接,能连接成功就表示此端口是开放的,不能连接成就表示此端口是关闭的。
以下TCP知识借鉴玄魂博客的 作者:高海峰 QQ:543589796的描述。
- TCP connect扫描:也称为全连接扫描,这种方式直接连接到目标端口,完成了TCP三次握手的过程,这种方式扫描结果比较准确,但速度比较慢而且可轻易被目标系统检测到。
- TCP SYN扫描:也称为半开放扫描,这种方式将发送一个SYN包,启动一个TCP会话,并等待目标响应数据包。如果收到的是一个RST包,则表明端口是关闭的,而如果收到的是一个SYN/ACK包,则表示相应的端口是打开的。
- Tcp FIN扫描:这种方式发送一个表示拆除一个活动的TCP连接的FIN包,让对方关闭连接。如果收到了一个RST包,则表明相应的端口是关闭的。
- TCP XMAS扫描:这种方式通过发送PSH、FIN、URG、和TCP标志位被设为1的数据包。如果收到了一个RST包,则表明相应的端口是关闭的