其实,写个扫描器也挺好玩的,牵涉到了RAW Socket编程,可以尽情地DIY数据包(当然,不符合数据包规则,比如checksum错误就没办法了),收获颇深。其中,我觉得用C语言写更有利于在编写过程中对加深对计算机网络的理解,特别是数据包细节。但是由于效率问题,还有Python真是太好用了(自从用了python,日常再也不想去碰C/C++了,虽然python也写的挺烂的)。话不多说,言归正传。

  学习信息安全的自然听说过nmap这种网络扫描神器,其中功能选项多,老少咸宜,不仅能满足网络管理员的日常,还能满足网络安全工程师的渗透测试,这个课程设计程度的扫描器自然不会有那么多功能,主要实现利用TCP和UDP的一些特性的进行IP段主机存活情况以及端口扫描。

  基本功能如下:

    1.发送udp包,检测一个极少使用的端口,对回传的ICMP包的进行分析,从而判断主机是否存活。

    2.利用TCP三次握手,通过是否连接成功,来判定端口是否开放,其中采用了多线程加快了扫描速度。

    3.通过RAW Socket的原生编程,对TCP标志位进行人工设置,对回复数据包的标志位进行分析,从而不需要TCP三次握手就可以对端口是否开放进行判定。部分方式如下

      i:通过SYN置1,检测回传的数据包的标志位是否为SYN/ACK

      ii:通过ACK置1,查看是否回传数据包,且数据包的标志位是否为RST

      iii:通过将所有标志位都置0,查看是否回传数据包,且数据包的标志位是否为RST

      iv:通过FIN+URG+PSH置1,查看是否回传数据包,且数据包的标志位是否为RST

  在编写功能之前,有必要写对IP,ICMP,TCP的包头进行解析,直接看代码:

  IP数据包头:

_fields_ = [
("ihl", c_ubyte, 4),
("version", c_ubyte, 4),
("tos", c_ubyte),
("len", c_ushort),
("id", c_ushort),
("offset", c_ushort),
("ttl", c_ubyte),
("protocol_num", c_ubyte),
("sum", c_ushort),
("src", c_ulong),
("dst", c_ulong)
]

  ICMP数据包头:

_fields_ = [
("type", c_ubyte),
("code", c_ubyte),
("checksum", c_ushort),
("unused", c_ushort),
("next_hop_mtu", c_ushort)
]

  TCP数据包头:

 _fields_ = [
("src_port", c_ushort),
("dst_port", c_ushort),
("seq", c_ulong),
("ack_seq", c_ulong),
("offset", c_ubyte),
("flag", c_ubyte),
("windows", c_ushort),
("checksum", c_ushort),
("point", c_ushort),
]

  TCP数据包头的 offset,flag 并不是真正的数据包结构,但是由于单字节细节处不好处理,直接写成上文那样了,所有结构非一言两语可以说完的,详情可参考《IP/TCP详解》。

  1.先从最简单的TCPconnect多线程端口扫描开始,基于部分防火墙的策略,应该对需要扫描的端口区间进行随机分配算法,来干扰防火墙的判断。当然,由于太懒了,就直接一路扫下去了。具体代码如下:

def portTest(ip,port,num):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
i = 0
while i <num:
try:
myport = i + port
s.connect(( "%s" %ip, myport ))
s.close()
print "%s:%d is open" % (ip,myport)
except BaseException,e:    
pass
i = i+1 def TcpConnect(subnet,port,num=1):
Port = int(port)
if num > 8:
for ip in IPNetwork(subnet):
for i in range(0,THREADNUM):
t = threading.Thread(target=portTest, args=(ip,Port+i*num/THREADNUM,num/THREADNUM)) #开了8个线程,
t.start()
else:
for ip in IPNetwork(subnet): #方便对区段进行扫描
portTest(ip,Port,num)

  总共开了八个线程,将端口段分成8份进行扫描。通过异常来退出对位打开的端口的连接,但是实际使用中,容易被网络发现,这种方法只能说是最为简单,但是不推荐使用。

  2.利用udp进行扫描。

  这里需要涉及到RAW socket的编程,《python黑帽》里关于udp扫描的代码写的非常好(其它的代码也写的不错,在里面也学习了很多python的技巧)。基本原理就是通过setsocketopt函数来设置网卡的混杂模式。进行嗅探,直接贴里面的代码:

def udp_sender(subnet,magic_message):
time.sleep(5)
sender = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for ip in IPNetwork(subnet):
try:
sender.sendto(magic_message, ("%s" % ip, 65211)) #对每个ip地址进行发包
except:
pass def ICMPecho(subnet):
if os.name == "nt":
socket_protocol = socket.IPPROTO_IP
else:
socket_protocol = socket.IPPROTO_ICMP
sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
sniffer.bind((host, 0))
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
if os.name == "nt": #跨平台必备
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
t = threading.Thread(target=udp_sender, args=(subnet,magic_message)) #线程用于发送数据包
t.start()
try:
while True:
raw_buffer = sniffer.recvfrom(65565)[0] #对收到的数据包进行检测
ip_header = IP(raw_buffer[0:20])
if ip_header.protocol == "ICMP":
offset = ip_header.ihl * 4
buf = raw_buffer[offset:offset+sizeof(ICMP)]
icmp_header = ICMP(buf)
if icmp_header.type == 3 and icmp_header.code == 3:
if IPAddress(ip_header.src_address) in IPNetwork(subnet):
if raw_buffer[len(raw_buffer) - len(magic_message):] == magic_message:
print "Host Up: %s" % ip_header.src_address
except KeyboardInterrupt:
if os.name == "nt":
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)

  3:最好玩的当然是构造数据包,通过自己构造数据包可以做很多非常geek的事情,比如DNS欺骗,ARP欺骗,SYN洪泛等等。先来看看怎么构造标志位。

def createTcpFlag(fin=0,syn=0,rst=0,psh=0,ack=0,urg=0):
tcp_flags = fin + (syn<<1) + (rst<<2) + (psh<<3) + (ack<<4) + (urg<<5)
return tcp_flags

  简单的移位操作就可以实现了对符号位的操作了。

   再看看怎么创建TCP数据包头。

def create_tcp_header(source_ip, dest_ip, dest_port,tcp_flag):
source = random.randrange(32000,62000,1)
seq = 0
ack_seq = 0
doff = 5
window = socket.htons (8192)
check = 0 #先将数据包的校验位置0
urg_ptr = 0
offset_res = (doff << 4) + 0
tcp_flags = tcp_flag
tcp_header = struct.pack('!HHLLBBHHH', source, dest_port, seq, ack_seq, offset_res, tcp_flags, window, check, urg_ptr)
  #TCP头在进行校验和时,需要有一个伪IP头,基本细节如下
source_address = socket.inet_aton( source_ip )
dest_address = socket.inet_aton( dest_ip )
placeholder = 0
protocol = socket.IPPROTO_TCP
tcp_length = len(tcp_header)
psh = struct.pack('!4s4sBBH', source_address, dest_address, placeholder, protocol, tcp_length);
psh = psh + tcp_header;
tcp_checksum = checksum(psh)
tcp_header = struct.pack('!HHLLBBHHH', source, dest_port, seq, ack_seq, offset_res, tcp_flags, window, tcp_checksum, urg_ptr)
return tcp_header

  IP数据包头部基本如上。可以结合

  create_tcp_header()和createTcpFlag()来操作数据包符号位,以实现基本功能3下的功能了。

  

Python之端口扫描器编写的更多相关文章

  1. python实现端口扫描器/DoS/DDoS

    整理github,梳理下Python小工具.以下是python实现的DoS/DDoS/端口扫描器(github). 一.DoS SYN Flood是当前最流行的DoS(拒绝服务攻击)与DdoS(分布式 ...

  2. Python开发端口扫描器

    首先是最常用的端口扫描器: 虽说有nmap等强大的工具,不过如果由于条件限制无法安装Nmap呢? 我这个脚本写的比较简单,默认扫描1-65535全部的端口 实际的话,可以根据需要自己修改脚本来实现定制 ...

  3. 再议perl写多线程端口扫描器

    再议perl写多线程端口扫描器 http://blog.csdn.net/sx1989827/article/details/4642179 perl写端口多线程扫描器 http://blog.csd ...

  4. 使用Python编写简单的端口扫描器的实例分享【转】

    转自 使用Python编写简单的端口扫描器的实例分享_python_脚本之家 http://www.jb51.net/article/76630.htm -*- coding:utf8 -*- #!/ ...

  5. Python脚本写端口扫描器(socket,python-nmap)

    目录 Socket模块编写 扫描给定主机是否开放了指定的端口 python-nmap模块编写 扫描给定ip或给定网段内指定端口是否开放 一个用python写的简单的端口扫描器,python环境为 3. ...

  6. Python与Hack之window下运行带参数的Python脚本,实现一个简单的端口扫描器

    1.前提是:windows已经配置好Python的环境变量: 2.进入cmd命令行模式: **输入python命令,检测是否环境配置好:显示这样说明配置环境变量没问题 **用cd命令进入Python脚 ...

  7. 『Python』 多线程 端口扫描器

    0x 00 Before Coding 当端口打开时,向端口发送 TCP SYN 请求,会返回一个 ACK 响应: 当端口关闭,返回的是 RST 响应: 0x 01 Coding  可以用 socke ...

  8. python端口扫描器

    吃了个火鸡面后感觉到了怀疑人生!!!!!!!!!妈耶,在也不吃了.思路都给辣没了!!! python端口扫描器代码如下: #-*-coding:utf-8 from socket import * i ...

  9. python实现FTP弱口令扫描器与简单端口扫描器

    python实现FTP弱口令扫描器与简单端口扫描器 目录 FTP弱口令扫描器 简单端口扫描器 参考: https://blog.csdn.net/rebelqsp/article/details/22 ...

随机推荐

  1. python负数除法与模运算

    1.负数除法: >>> print 45/76>>> print -45/7-7 >>> print 45/-7-7 >>> p ...

  2. JavaSE复习(一)继承多态与常用API

    继承与多态 在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式: 直接通过子类对象访问成员变量:等号左边是谁,就优先用谁,没有则向上找 间接通过成员方法访问成员变量:该方法属于 ...

  3. poj 1840 枚举

    Eqs Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 13967   Accepted: 6858 Description ...

  4. 使用“\n\t”将多行字符串拼接起来

    以前js拼接字符串有好多 \n \t 不使用ES6 使用"\n\t"将多行字符串拼接起来: var roadPoem = 'Then took the other, as just ...

  5. PHP文件操作函数及文件指针理解

    知识点: 一.fopen(),文件打开函数,读写参数有: 1.R  : 只读,指针在文件开头 2.r+:读写,指针同上 3.W :只写,写入前会删除文件内容,然后指针回到文件开头,文件不存在则创建 4 ...

  6. 有趣的数(number)

    有趣的数(number) 题目描述 这些天 nodgd 在研究一类有趣的数.定义函数 f(n) f(n) f(n) 表示 n n n 在十进制表示下的数字之和.如果一个正整数 n n n 满足 f(n ...

  7. Codeforces Round #352 (Div. 2) A

    A. Summer Camp time limit per test 1 second memory limit per test 256 megabytes input standard input ...

  8. js实现封装和继承

    封装(模拟对象) http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html 继承 htt ...

  9. hdu 5072 计数+容斥原理

    /* 题意: 给出n个数(n<100000), 每个数都不大于100000,数字不会有重复.现在随意抽出3个,问三个彼此互质 或者 三个彼此不互质的数目有多少. 思路: 这道题反着想,就是三个数 ...

  10. 理解S12(X)架构中的地址映射方案

    目录 1. 介绍 2. CPU 本地地址 3. 分页窗口 4. 内存页 5. 控制各个对象在内存中放置的位置 介绍 在一个S12或S12X架构中,很有必要分清楚两种类型的内存地址:banked和non ...