TCP/IP & Scapy 发包 ICMP扫描

TCP/IP的分层

TCP/IP协议族中不同层次的协议

TCP/IP 基础

数据包

  • 包可以说是全能性术语;
  • 帧用于表示数据链路层中包的单位;
  • 数据包是 IP 和 UDP 等网络层以上的分层中包的单位;
  • 段则表示 TCP 数据流中的信息;
  • 消息是指应用协议中数据的单位。

数据包首部

数据的封装

Ethernet头

首先是目的MAC 6个字节,然后源MAC6个字节,接下来数据类型两个字节。 然后是数据长度,46-1500字节。对于不定长的数据包,帧最后还有4个字节的FCS(Frame check sequence)

ARP

  • op:取值位1或2 1为发送 2为响应
  • hwsrc:源mac地址
  • psrc:源ip地址
  • hwdst:目的mac地址
  • pdst:目的ip地址

IP头部

  • 版本号(Version):4bit。表明IP协议的版本号。一般为0100(IPv4),0110(IPv6)
  • IP包头长度(Header Length):4bit。用于描述IP包头长度,因为IP包头长度是可变的。
  • 服务类型(Type of Service):长度8比特。
  • IP包总长(Total Length):16bit。 以字节为单位计算的IP包的长度 (包括头部和数据),所以IP包最大长度65535字节。
  • 标识符(Identifier):16bit。用于数据包在分段重组时标识其序列号。将数据分段后,打包成IP包,IP包因走的路由上不同,会产生不同的到达目地的时间,到达目地的后再根据标>识符进行重新组装还原。该字段要与标志、段偏移一起使用的才能达到分段组装的目标。
  • 标志(Flags):16bit。三位从左到右分别是MF、DF、未用。MF=1表示后面还有分段的数据包,MF=0表示没有更多分片(即最后一个分片)。DF=1表示路由器不能对该数据包分段,DF=0表示数据包可以被分段。
  • 片偏移(Fragment Offset):13bit。表示该IP包在该组分片包中位置,接收端靠此来组装还原IP包。
  • 生存时间(TTL):8bit。当IP包在网络上传送时,每经过一个路由器,TTL就自动减一。值为0时,则丢弃报文。防止报文进入环路。
  • 协议(Protocol):8bit。标识IP头后面的报文协议类型
协议号 协议
1 ICMP
2 IGMP
6 TCP
17 UDP
88 IGRP
89 OSPF
  • 头校验和(Header Checksum):16bit。用来做IP头部的正确性检测,但不包含数据部分。由于路由器会改变TTL,所以路由器会为每个通过的数据包重新计算这个值。
  • 源和目的地址(Source and Destination Addresses):这两个地段都是32比特。标识了这个IP包的起源和目标地址。要注意除非使用NAT,否则整个传输的过程中,这两个地址不会改

变。

传输层中的 TCP 和 UDP

  • TCP 是面向连接的、可靠的流协议。
  • UDP 是不具有可靠性的数据报协议。

TCP数据报的首部

  • 源端口(Source Port):16bit, 表示报文发送方的端口号

  • 目的端口(Destination port): 16bit,表示报文接收方的端口号

  • 序列号(SN):32bit,标识了TCP报文中第一个byte在对应方向的传输中对应的字节序号。

  • 应答号(ACK):32bit,标识了报文发送端期望接收的字节序列。

  • 数据偏移·首部长度(Header Length):4bit,指示TCP头的长度,即数据从何处开始。

  • 保留(Reserved):4bit,这些位必须是0。

  • 标志(Code Bits):8bit

    • CWR(Congestion Window Reduce):拥塞窗口减少标志被发送主机设置,用来表明它接收到了设置ECE标志的TCP包,发送端将通过降低发送窗口的大小来降低发送速率
    • ECE(ECN Echo):ECN响应标志被用来在TCP3次握手时表明一个TCP端是否具备ECN功能,并且表明接收到的TCP包的IP头部的ECN被设置为11。更多信息请参考RFC793。
    • URG(Urgent):表示紧急(The urgent pointer) 指针是否有效。
    • ACK(Acknowledgment):1表示这是一个确认的TCP包, 0则不是确认包。
    • PSH(Push):该标志置位时,一般是表示发送端缓存中已经没有待发送的数据,接收端不将该数据进行队列处理,而是尽可能快将数据转由应用处理。
    • RST(Reset):用于复位相应的TCP连接。通常在发生异常或者错误的时候会触发复位TCP连接。
    • SYN(Synchronize):表示同步序列编号(Synchronize Sequence Numbers)是否有效。该标志仅在三次握手建立TCP连接时有效。它提示TCP连接的服务端检查序列编号,该序列编号为TCP连接发起端(一般是客户端)的初始序列编号。在这里,可以把TCP序列编号看作是一个范围从0到4,294,967,295的32位计数器。通过TCP连接交换的数据中每一个字节都经过序列编号。>在TCP报头中的序列编号栏包括了TCP分段中第一个字节的序列编号。
    • FIN(Finish):带有该标志置位的数据包用来结束一个TCP会话,但对应端口仍处于开放状态,准备接收后续数据。当FIN标志有效的时候我们称呼这个包为FIN包。
  • 窗口大小(Window Size):16bit,表示从Ack Number开始还能接收多少字节的数据量,即当前接收端的接收窗口还有多少剩余空间。用于TCP的流量控制。

  • 校验和(Checksum):16bit。发送端基于数据内容计算一个数值,接收端要与发送端数值结果完全一样,才能证明数据的有效性。接收端checksum校验失败的时候会直接丢掉这个数据包

。CheckSum是根据伪头+TCP头+TCP数据三部分进行计算的。

  • 紧急指针(Urgent Pointer):16位,在URG标志设置了时才有效。与序号字段的值相加后表示最后一个紧急数据的下一字节的序号,可以说这个字段是紧急指针相对当前序号的偏移>。
  • 选项(Option):长度不定,但长度必须以是32bits的整数倍。常见的选项包括MSS、SACK、Timestamp等等,后续的内容会分别介绍相关选项。

UDP数据报的首部

Scapy 模块

接收与发送数据包

名 称 描述 举例
srp() 发送二层数据包,并且等待响应 同sr()
srp1() 发送二层数据包,返回只答复或者发送的包的详细信息 `srp1(pkt, timeout=1, verbose=0)`
sendp() 指定网卡接口,发送二层数据包,不负责接收。sendp()函数允许自定义以太网层 `sendp(pkt,iface="eth0",loop=1,inter=1 )`
sr() 发送三层数据包,等待接收一个或多个数据包的回复 `sr(pkt, filter=N, iface=N)`
sr1() 发送三层数据包,并仅仅只等待接收一个数据包的响应 `sr1(pkt, inter=0, loop=0, count=1, iface='en0')` loop 循环、inter 发送间隔、verbose 是否显示详细信息
send() 仅仅发送三层数据包,不负责接收,系统会自动处理路由和二层信息。send()函数允许自定义网络层 `send(IP(dst="192.168.115.188")/ICMP())`
srloop() 在一个循环中发送数据包,并打印每个回复 `srloop(pkt, timeout=N, count=N)`
get_if_hwaddr() 获取本地网络接口mac地址
get_if_addr() 获取本地网络接口ip地址
getmacbyip() 通过ip获取mac地址

APR() 构造ARP数据包
IP() 构造IP数据包 三层
ICMP() 构造ICMP数据包
Ether() 构造以太网数据包  二层

sniff嗅探包

  • count:抓包的数量,0表示无限制;
  • store:保存抓取的数据包或者丢弃;
  • prn:为每一个数据包定义一个函数,如果返回了什么,则显示。例如:prn = lambda x: x.summary();
  • offline:从 pcap 文件读取数据包,而不进行嗅探;
  • timeout:在给定的时间后停止嗅探,默认为 None;
  • L2socket:使用给定的 L2socket;
  • opened_socket:对指定的对象使用 .recv() 进行读取;
  • stop_filter:定义一个函数,决定在抓到指定数据包后停止抓包,如:stop_filter = lambda x: x.haslayer(TCP);
  • iface:指定抓包的接口
sniff(count=0, store=1, timeout=N)
pkts=sniff(count=100, iface="eth0")

ICMP 扫描

# _*_ coding=utf-8 _*_
from scapy.all import *
import random
import threading

def scan(sip,dip):
    pkt = Ether(dst="ff:ff:ff:ff:ff:ff")/IP(tos = 0x04, ttl = 64,proto = "icmp", id = random.randint(1,1000), src = sip, dst = dip)/ICMP()
    res = srp1(pkt, timeout = 2, retry=0,verbose=False)
    if res:
        if res[ICMP].type == 0: #ICMP type为0表示是ICMP echo-reply
            print ('[+]IP:主机%s echo-reply. MAC: %s' %(res[IP].src,res[Ether].src))

if __name__ == '__main__':
    sip = get_if_addr("en0") # 获取本地网卡(wlp3s0)ip地址
    for i in range(1,255):
        dip = "192.168.0."+str(i) 
        t = threading.Thread(target = scan, args = (sip,dip,))
        t.start()


文章作者: 子杰
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 子杰 ! !
评论
 上一篇
渗透测试中常见的端口 渗透测试中常见的端口
渗透测试中常见的端口端口对应服务及漏洞 端口详解: 21 ftp 22 SSH 23 Telnet 80 web 80-89 web 161 SNMP 389 LDAP 443 SSL心脏滴血以及一些
2019-06-25
下一篇 
文件上传漏洞详解 文件上传漏洞详解
由于文件上传功能实现代码没有严格限制用户上传的文件后缀、文件头、文件内容等,导致允许攻击者向某个可通过Web访问的目录上传任意脚本文件(jsp/php/asp等),并能够姜这些文件传递给服务器解释执行
2019-07-12
  目录