Linux 内核 TCP MSS 机制详细分析 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

Linux 内核 TCP MSS 机制详细分析

申博_新闻事件 申博 124次浏览 未收录 0个评论

媒介

上周Linux内核修复了4个CVE破绽[1],个中的CVE-2019-11477觉得是一个很厉害的Dos破绽,不过由于有其他事打断,所以希望的速率比较慢,这时期网上已有相干的剖析文章了。[2][3]

而我在尝试复现CVE-2019-11477破绽的历程当中,在第一步设置MSS的题目上就遇到题目了,没法到达预期效果,然则如今公然的剖析文章却没对该部份内容举行详细剖析。所以本文将经由历程Linux内核源码对TCP的MSS机制举行详细剖析。

测试环境

1. 存在破绽的靶机

操作体系版本:Ubuntu 18.04

内核版本:4.15.0-20-generic

地点:192.168.11.112

内核源码:

$ sudo apt install linux-source-4.15.0
$ ls /usr/src/linux-source-4.15.0.tar.bz2

带符号的内核:

$ cat /etc/apt/sources.list.d/ddebs.list
deb http://ddebs.ubuntu.com/ bionic main
deb http://ddebs.ubuntu.com/ bionic-updates main
$ sudo apt install linux-image-4.15.0-20-generic-dbgsym
$ ls /usr/lib/debug/boot/vmlinux-4.15.0-20-generic

封闭内核地点随机化(KALSR):

# 内核是经由历程grup启动的,所以在grup设置文件中,内核启动参数里加上nokaslr 
$ cat /etc/default/grub |grep -v "#" | grep CMDLI
GRUB_CMDLINE_LINUX_DEFAULT="nokaslr"
GRUB_CMDLINE_LINUX=""
$ sudo update-grub

装一个nginx,供测试:

$ sudo apt install nginx

2. 宿主机

操作体系:MacOS

Wireshark:抓流量

虚拟机:VMware Fusion 11

调试Linux虚拟机:

$ cat ubuntu_18.04_server_test.vmx|grep debug
debugStub.listen.guest64 = "1"

编译gdb:

$ ./configure --build=x86_64-apple-darwin --target=x86_64-linux --with-python=/usr/local/bin/python3
$ make
$ sudo make install
$ cat .zshrc|grep gdb
alias gdb="~/Documents/gdb_8.3/gdb/gdb"

gdb举行长途调试:

$ gdb vmlinux-4.15.0-20-generic
$ cat ~/.gdbinit
define gef
source ~/.gdbinit-gef.py
end

define kernel
target remote :8864
end

3. 进击机械

本身一样平常运用的Linux装备就好了

地点:192.168.11.111

一样平常习气运用Python的,须要装个scapy组织自定义TCP包

自定义SYN的MSS选项

有三种要领能够设置TCP SYN包的MSS值

1. iptable

# 增添划定规矩
$ sudo iptables -I OUTPUT -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 48
# 删除
$ sudo iptables -D OUTPUT -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 48

2. route

# 检察路由信息
$ route -ne
$ ip route show
192.168.11.0/24 dev ens33 proto kernel scope link src 192.168.11.111 metric 100
# 修正路由表
$ sudo ip route change 192.168.11.0/24 dev ens33 proto kernel scope link src 192.168.11.111 metric 100 advmss 48
# 修正路由表信息就是在上面show的效果背面加上 advmss 8

3. 直接发包设置

PS:运用scapy发送自定义TCP包须要ROOT权限

from scapy.all import *ip = IP(dst="192.168.11.112")tcp = TCP(dport=80, flags="S",options=[('MSS',48),('SAckOK', '')])

flags选项S示意SYN,A示意ACK,SA示意SYN, ACK

scapy中TCP可设置选项表:

通过暴露的Docker API渗透容器:AESDDoS僵尸网络恶意软件分析

概述 在当今的互联网中,错误配置已经不是一个新鲜的话题。然而,网络犯罪分子正持续将其作为一种行之有效的方式来获取组织的计算机资源,并进而将其用于恶意目的,由此导致了一个非常值得关注的安全问题。在本篇文章中,我们将详细介绍一种攻击类型,其中流行的DevOps工具Docker Engine-Community的开源版本中存在一个API配置错误,允许攻击者渗透容器,并运行恶意软件变种。该变种源自Linux僵尸网络恶意软件AESDDoS,由我们部署的蜜罐捕获,检测为“Backdoor.Linux.DOFLOO.AA”。 在容器主机上运行的Docker API允许主机接收所

TCPOptions = (
{ 
    0 : ("EOL",None),
    1 : ("NOP",None),
    2 : ("MSS","!H"),
    3 : ("WScale","!B"),
    4 : ("SAckOK",None),
    5 : ("SAck","!"),
    8 : ("Timestamp","!II"),
    14 : ("AltChkSum","!BH"),
    15 : ("AltChkSumOpt",None),
    25 : ("Mood","!p"),
    254 : ("Experiment","!HHHH")
},
{ 
    "EOL":0,
    "NOP":1,
    "MSS":2,
    "WScale":3,
    "SAckOK":4,
    "SAck":5,
    "Timestamp":8,
    "AltChkSum":14,
    "AltChkSumOpt":15,
    "Mood":25,
    "Experiment":254
})

然则这个会有一个题目,在运用Python发送了一个SYN包今后,内核会自动带上一个RST包,查过材料后,发如今新版体系中,关于用户发送的未完成的TCP握手包,内核会发送RST包停止该衔接,应当是为了防备举行SYN Floor进击。解决方法是运用iptable过滤RST包:

$ sudo iptables -A OUTPUT -p tcp --tcp-flags RST RST -s 192.168.11.111 -j DROP

关于MSS的深入研究

关于该破绽的细节,别的文章中已剖析过了,这里简朴的提一下,该破绽为uint16溢出:

tcp_gso_segs 范例为uint16
tcp_set_skb_tso_segs:tcp_skb_pcount_set(skb, DIV_ROUND_UP(skb->len, mss_now));skb->len的最大值为17 * 32 * 1024mss_now的最小值为8
>>> hex(17*32*1024//8)'0x11000'>>> hex(17*32*1024//9)'0xf1c7'

所以在mss_now小于即是8时,才发作整型溢出。

深入研究的缘由是由于举行了以下的测试:

进击机械经由历程iptables/iproute敕令将MSS值为48后,运用curl要求靶机的http效劳,然后运用wireshark抓流量,发明效劳器返回的http数据包确实被分割成小块,然则只小到36,离料想的8有很大的差异

这个时刻我挑选经由历程审计源码和调试来深入研究为啥MSS没法到达我的预期值,SYN包中设置的MSS值到代码中的mss_now的历程当中发作了啥?

随机举行源码审计,对发作溢出的函数tcp_set_skb_tso_segs举行回溯:

tcp_set_skb_tso_segs <- tcp_fragment <- tso_fragment <- tcp_write_xmit
末了发明,传入tcp_write_xmit函数的mss_now都是经由历程tcp_current_mss函数举行盘算的

随后对tcp_current_mss函数举行剖析,症结代码以下:

# tcp_output.c
tcp_current_mss -> tcp_sync_mss:mss_now = tcp_mtu_to_mss(sk, pmtu);tcp_mtu_to_mss:/* Subtract TCP options size, not including SACKs */return __tcp_mtu_to_mss(sk, pmtu) -
           (tcp_sk(sk)->tcp_header_len - sizeof(struct tcphdr));__tcp_mtu_to_mss:if (mss_now < 48)
    mss_now = 48;return mss_now;

看完这部份源码后,我们对MSS的寄义就有一个深入的明白,起首说一说TCP协定:

TCP协定包含了协定头和数据,协定头包含了牢固长度的20字节和40字节的可选参数,也就是说TCP头部的最大长度为60字节,最小长度为20字节。

在__tcp_mtu_to_mss函数中的mss_now为我们SYN包中设置的MSS,从这里我们能看出MSS最小值是48,经由历程对TCP协定的明白和对代码的明白,能够晓得SYN包中MSS的最小值48字节示意的是:TCP头可选参数最大长度40字节 + 数据最小长度8字节。

然则在代码中的mss_now示意的是数据的长度,接下来我们再看该值的盘算公式。

tcphdr构造:

struct tcphdr {
    __be16  source;
    __be16  dest;
    __be32  seq;
    __be32  ack_seq;#if defined(__LITTLE_ENDIAN_BITFIELD)
    __u16   res1:4,
        doff:4,
        fin:1,
        syn:1,
        rst:1,
        psh:1,
        ack:1,
        urg:1,
        ece:1,
        cwr:1;#elif defined(__BIG_ENDIAN_BITFIELD)
    __u16   doff:4,
        res1:4,
        cwr:1,
        ece:1,
        urg:1,
        ack:1,
        psh:1,
        rst:1,
        syn:1,
        fin:1;#else#error  "Adjust your <asm/byteorder.h> defines"#endif  
    __be16  window;
    __sum16 check;
    __be16  urg_ptr;};

该构造体为TCP头牢固构造的构造体,大小为20bytes

变量tcp_sk(sk)->tcp_header_len示意的是本机发出的TCP包头部的长度。

因而我们获得的盘算mss_now的公式为:SYN包设置的MSS值 – (本机发出的TCP包头部长度 – TCP头部牢固的20字节长度)

所以,假如tcp_header_len的值能到达最大值60,那末mss_now就可以被设置为8。那末内核代码中,有方法让tcp_header_len到达最大值长度吗?随后我们回溯该变量:

# tcp_output.c
tcp_connect_init:
tp->tcp_header_len = sizeof(struct tcphdr);
    if (sock_net(sk)->ipv4.sysctl_tcp_timestamps)
        tp->tcp_header_len += TCPOLEN_TSTAMP_ALIGNED;

#ifdef CONFIG_TCP_MD5SIG
    if (tp->af_specific->md5_lookup(sk, sk))
        tp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED;
#endif

所以在Linux 4.15内核中,在用户不干涉干与的情况下,内核是不会发出头部大小为60字节的TCP包。这就致使了MSS没法被设置为最小值8,终究致使该破绽没法应用。

总结

我们来总结一下全部流程:

1. 进击者组织SYN包,自定义TCP头部可选参数MSS的值为48

2. 靶机(遭到进击的机械)接收到SYN要求后,把SYN包中的数据保留在内存中,返回SYN,ACK包。

3. 进击者返回ACK包

三次握手完成

随后依据差别的效劳,靶机主意向进击者发送数据或许接收到进击者的要求后向进击者发送数据,这里就假定是一个nginx http效劳。

1. 进击者向靶机发送要求:GET / HTTP/1.1。

2. 靶机接收到要求后,起首盘算出tcp_header_len,默许即是20字节,在内核设置sysctl_tcp_timestamps开启的情况下,增添12字节,假如编译内核的时刻挑选了CONFIG_TCP_MD5SIG,会再增添18字节,也就是说tcp_header_len的最大长度为50字节。

3. 随后须要盘算出mss_now = 48 – 50 + 20 = 18

这里假定一下该破绽能够应用胜利的场景:有一个TCP效劳,本身设定了TCP可选参数,而且设置满了40字节,那末进击者才有能够经由历程组织SYN包中的MSS值来对该效劳举行Dos进击。

随后我对Linux 2.6.29至今的内核举行审计,mss_now的盘算公式都一样,tcp_header_len长度也只会加上时候戳的12字节和md5值的18字节。

原文地点: https://www.4hou.com/info/news/18908.html


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明Linux 内核 TCP MSS 机制详细分析
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址