Scapy—SYN扫描


Scapy—SYN扫描

一、知识准备

TCP SYN 扫描以TCP三次握手为基础,通过接受服务端返回的ACK状态来判断端口的工作状态,此后SYN 扫描刻意建立不完整的TCP连接,来逃避服务端的记录。具体SYN连接流程如下

接着使用wireshark进行抓包分析,可以看到流程与上面分析的一样,只是更具体了

二、构造数据包

SYN扫描属于TCP连接的一部分,于是需要涉及到TCP部分,所以在使用的时候直接从网络层开始即可。

>>> p = IP(dst="10.87.51.19")/TCP(dport=22,flags="S")
>>> s = sr(p)
Begin emission:
..Finished sending 1 packets.
*
Received 3 packets, got 1 answers, remaining 0 packets
>>> s
(<Results: TCP:1 UDP:0 ICMP:0 Other:0>,
 <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>)

在之前博客已经提到过,接收到的数据报一部分是没有得到回应的,一部分是有回应的,所以重新构造两个变量,分别接受两个部分

>>> p = IP(dst="10.87.51.19")/TCP(dport=22,flags="S")
>>> s,_ = sr(p)
Begin emission:
Finished sending 1 packets.
*
Received 1 packets, got 1 answers, remaining 0 packets
>>> s
<Results: TCP:1 UDP:0 ICMP:0 Other:0>

现在变量 s 只接受到了有回应的一部分数据包,因为只有一个包,所以直接查看第一个就行

>>> s[0]
(<IP  frag=0 proto=tcp dst=10.87.51.19 |<TCP  dport=ssh flags=S |>>,
 <IP  version=4 ihl=5 tos=0x0 len=44 id=0 flags=DF frag=0 ttl=64 proto=tcp chksum=0xbffa src=10.87.51.19 dst=10.87.51.17 |<TCP  sport=ssh dport=ftp_data seq=4107690571
 ack=1 dataofs=6 reserved=0 flags=SA window=14600 chksum=0x8cef urgptr=0 options=[('MSS', 1460)] |<Padding  load='\x00\x00' |>>>)

可以看到,在这个数据包中还涉及到发送的部分跟接受的部分,这里只看接受到的部分

>>> s[0][1]
<IP  version=4 ihl=5 tos=0x0 len=44 id=0 flags=DF frag=0 ttl=64 proto=tcp chksum=0xbffa src=10.87.51.19 dst=10.87.51.17 |<TCP  sport=ssh dport=ftp_data seq=4107690571
ack=1 dataofs=6 reserved=0 flags=SA window=14600 chksum=0x8cef urgptr=0 options=[('MSS', 1460)] |<Padding  load='\x00\x00' |>>>

上面已经提到了,连接成功的包是SYNACK ,也就是 SA ,能够看到,在TCP部分有相关内容,使用getlayer(TCP)可以把TCP部分拿出来,使用fields 可以看到这是一个字典形式的内容

 >>> s[0][1].getlayer(TCP)
<TCP  sport=ssh dport=ftp_data seq=4107690571 ack=1 dataofs=6 reserved=0 flags=SA window=14600 chksum=0x8cef urgptr=0 options=[('MSS', 1460)] |<Padding  load='\x00\x00
' |>>
>>> s[0][1].getlayer(TCP).fields
{'sport': 22,
 'dport': 20,
 'seq': 4107690571,
 'ack': 1,
 'dataofs': 6,
 'reserved': 0,
 'flags': <Flag 18 (SA)>,
 'window': 14600,
 'chksum': 36079,
 'urgptr': 0,
 'options': [('MSS', 1460)]}

这里我们要判断是否连接成功也就是判断上面这个字典中的 flags 这个字段的内容是什么,从字典中取出内容只需要提取指定值对应的键

>>> s[0][1].getlayer(TCP).fields['flags']
<Flag 18 (SA)>

看到这里面有两个值,来判断一下,用哪个是对的

>>> if s[0][1].getlayer(TCP).fields['flags'] == "SA":
...:    print("yes")
yes
>>> if s[0][1].getlayer(TCP).fields['flags'] == 18:
...:    print("yes")
...:
yes

可以看到,这两个值都是可以用的,只不过是形式不同而已

三、代码编写

代码里面添加了装饰器用来查看代码所用时间,如果不喜欢的话可以删掉,在Linux下面还可以使用 time -p 参数来查看代码运行时间

#!/usr/bin/python3
# -*- coding: utf-8 -*- 
# --author:valecalida--
# Edit time: 2020/4/23 12:20
from scapy.layers.inet import TCP, IP, ICMP, sr1
from threading import Thread
from random import randint
from time import time
import logging
import sys
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)


def timeit(f):
    def wrapper(*args, **kwargs):
        start_time = time()
        res = f(*args, **kwargs)
        end_time = time()
        print("%s函数运行时间为:%.8f" % (f.__name__, end_time - start_time))
        return res
    return wrapper


def random_id():
    return randint(1, 65535)


def scan_single(host):
    print("[..] Detecting whether the target is alive...")
    packet = IP(dst=host, ttl=64, id=random_id())/ICMP(id=random_id(), seq=random_id())
    response = sr1(packet, timeout=1, verbose=0)
    if response:
        return 2


@timeit
def syn_scan(target):
    for port in range(1, 201):
        response = sr1(IP(dst=target)/TCP(dport=port, flags="S"), timeout=1, verbose=False)
        if response[0][1].getlayer(TCP).fields['flags'] == 18:
            print("\t[+] Port: %s is opened!" % str(response[0][1].getlayer(TCP).fields['sport']))


def main():
    if scan_single(sys.argv[1]) == 2:
        print("[+] The target is alive!")
        t = Thread(target=sys_scan, args=[sys.argv[1]])
        t.start()
    else:
        print("[-] The target is unreachable!")


if __name__ == '__main__':
    t1 = time()
    main()

这里扫描200个端口,看看速度怎么样,控制台输出如下:

root@kali:~/Desktop# python3 `SYN`_Scan.py 10.87.51.19
[..] Detecting whether the target is alive...
[+] The target is alive!
    [+] Port: 22 is opened!
    [+] Port: 80 is opened!
    [+] Port: 111 is opened!
sys_scan函数运行时间为:2.89476037

可以看到程序扫描200个端口就花费了约3秒的时间,这是由于SYN连接机制决定的,那么如果进行全端口扫描的话,这个数字可能要番几十番了,在次只作为学习的一点记录。


文章作者: valecalida
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 valecalida !
评论
  目录