不按顺序来的 TCP 包

栏目: 服务器 · 发布时间: 5年前

内容简介:关于 TCP 建立连接和断开连接的流程,很多人都能大致说出来,可以参考正常的数据传输是在三次握手结束之后进行的,但是如果打破了这个流程,数据传输仍然可能成功,而部分防火墙 IDS 就可能被绕过,下面的两个例子来自 https://github.com/kirillwow/ids_bypass。Suricata IDS 在 4.0.4 版本之前存在这个问题

关于 TCP 建立连接和断开连接的流程,很多人都能大致说出来,可以参考 协议森林

正常的数据传输是在三次握手结束之后进行的,但是如果打破了这个流程,数据传输仍然可能成功,而部分防火墙 IDS 就可能被绕过,下面的两个例子来自 https://github.com/kirillwow/ids_bypass。

CVE-2018-6794

# 客户端开始三次握手 发送 SYN
Client    ->  [SYN] [Seq=0 Ack=0]           ->  Evil Server
# 服务器端正常的响应了 SYN-ACK
Client    <-  [SYN, ACK] [Seq=0 Ack=1]      <-  Evil Server
# 但是服务器端在握手结束之前就发送了 PSH,里面包含了一些数据
Client    <-  [PSH, ACK] [Seq=1 Ack=1]      <-  Evil Server
# 服务器端主动关闭了连接
Client    <-  [FIN, ACK] [Seq=83 Ack=1]     <-  Evil Server
# 三次握手完成
Client    ->  [ACK] [Seq=1 Ack=84]          ->  Evil Server
# 客户端正常的发送数据
Client    ->  [PSH, ACK] [Seq=1 Ack= 4]     ->  Evil Server

Suricata IDS 在 4.0.4 版本之前存在这个问题

RST 导致的绕过

有些 Windows 客户端在收到 RST 包之后,如果紧接着又收到了其他的 TCP 数据,那仍然是可以读取和处理的,有些 IDS 正确处理了这个问题,有的在收到 RST 包之后就停止了检查 TCP 包。

# Client starts a TCP 3-way handshake
Client    ->  [SYN] [Seq=0 Ack=0]           ->  Evil Server
# Server responses with TCP RST
Client    <-  [RST, ACK] [Seq=0x0 Ack=1]    <-  Evil Server
# And SYN-ACK shortly after RST
Client    <-  [SYN, ACK] [Seq=1 Ack=1]      <-  Evil Server
           ... 三次握手继续 ...

Suricata IDS(全版本?)存在这个问题。对于 UDP 数据包,也有一个类似的问题。

应用

某些云服务器厂商会实时的去过滤每台机器的 HTTP 请求的域名,也就是 Host 字段,一旦发现是没有[[(备)]]案的,就会返回一个拦截页面,怎么绕过这个呢。经过测试发现某云应该是不检测 HTTPS的,如果可以让 80 端口重定向到 443,然后设置 HSTS 头,这样基本长时间内浏览器就不会再访问 80 端口了,虽然 SSL SNI 和 证书中也是含有域名信息的。

访问 80 端口,发现三次握手是正常进行的,而拦截发生在客户端发送了 HTTP 请求包之后,这也说明,防火墙不是无条件封禁的和屏蔽端口的,而是实时的过滤。如果可以抢在防火墙发包之前发送,那就可以实现重定向了。

写了一个 Python 的脚本来完成这个事情

# coding=utf-8
from scapy.all import IP, TCP, send, sniff

SERVER_DOMAIN = "example.me"
SERVER_PORT = 4445

FIN = 0x01
SYN = 0x02
ACK = 0x10


def build_synack(syn):
    seq = 1
    # 确认 SYN
    ack = syn[TCP].seq + 1

    ip = IP(src=syn[IP].dst, dst=syn[IP].src)
    tcp = TCP(
            sport=syn[IP].dport,
            dport=syn[TCP].sport,
            flags="SA",
            seq=seq,
            ack=ack,
            options=[("MSS", 1460)]
    )
    return ip / tcp


def build_finack(syn):
    """
    带重定向指令的包
    """
    seq = 2
    ack = syn[TCP].seq + 1

    ip = IP(src=syn[IP].dst, dst=syn[IP].src)
    tcp = TCP(
            sport=syn[IP].dport,
            dport=syn[TCP].sport,
            flags="FA",
            seq=seq,
            ack=ack,
            options=[("MSS", 1460)]
    )
    resp = b"HTTP/1.1 307 Internal Redirect\r\n" \
           b"Content-Length: 0\r\n" \
           b"Location: https://%s:443\r\n" \
           b"Strict-Transport-Security: max-age=31536000\r\n" \
           b"\r\n" % SERVER_DOMAIN
    return ip / tcp / resp


def build_ack(p):
    seq = 3
    ack = p[TCP].seq + 1

    ip = IP(src=p[IP].dst, dst=p[IP].src)
    tcp = TCP(
            sport=p[IP].dport,
            dport=p[TCP].sport,
            flags="A",
            seq=seq,
            ack=ack,
            options=[("MSS", 1460)]
    )
    return ip / tcp


def handle_packet(p):
    # 如果是 SYN 就回复 SYN-ACK 和 FIN-ACK
    if p[TCP].flags & SYN and not p[TCP].flags & ACK:
        send(build_synack(p))
        print("SYN ACK sent")
        send(build_finack(p))
        send("FIN ACK sent")
    elif p[TCP].flags & FIN and p[TCP].flags & ACK:
        # 如果不 ACK,客户端可能一直重传
        send(build_ack(p))
        send("ACK sent")


if __name__ == "__main__":
    # 对于 TCP 和 SERVER PORT 端口的包,回调 handle_packet 函数
    sniff(filter="tcp and port %d" % SERVER_PORT, prn=handle_packet)

使用 scapy 框架,监听一个端口,在接收到 SYN 包之后,按照正常的握手流程返回 SYN-ACK,然后不等接收到 ACK 就继续发送 FIN-ACK,告诉客户端我要断开连接了,然后在这个包中包含有重定向的 HTTP 包。

在服务器端视角看是这样的

不按顺序来的 TCP 包

在客户端视角看是这样的

不按顺序来的 TCP 包

42 号包是代码的重定向,47 号包就是防火墙的重定向,可以看到 TTL 明显不一致,而且 seq 被我们代码扰乱,导致被认为 out-of-order 了。

不按顺序来的 TCP 包

因为 scapy 是用户态的,防止内核不知道整个连接流程而发送 rst 包,可以使用下面的命令屏蔽掉

iptables -A OUTPUT -p tcp --tcp-flags RST RST -s 172.21.0.3 -j DROP

也有人使用内核模块实现了这个功能

https://github.com/ptpt52/hstshack


以上所述就是小编给大家介绍的《不按顺序来的 TCP 包》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Orange'S:一个操作系统的实现

Orange'S:一个操作系统的实现

于渊 / 电子工业出版社 / 2009-6 / 69.00元

《Orange S:一个操作系统的实现》从只有二十行的引导扇区代码出发,一步一步地向读者呈现一个操作系统框架的完成过程。书中不仅关注代码本身,同时关注完成这些代码的思路和过程。本书不同于其他的理论型书籍,而是提供给读者一个动手实践的路线图。读者可以根据路线图逐步完成各部分的功能,从而避免了一开始就面对整个操作系统数万行代码时的迷茫和挫败感。书中讲解了大量在开发操作系统中需注意的细节问题,这些细节不......一起来看看 《Orange'S:一个操作系统的实现》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具