CVE-2019-11477 SACK Panic漏洞利用分析

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/dog250/article/details/95252740

一到下大雨天就想做点什么有意思的。皮鞋不会进水,因为根本就没有皮鞋,自然也就不会湿…

疯子带着小小去旅游了,家里就剩我一个,所以自然也就回来继续工作咯,不然还能干什么。当然,这也不是工作,算自娱自乐吧。当我工作的时候,我感到充实,我将休息,又觉得空虚,不工作也不休息,只能随便玩玩了。


前面写了几篇关于CVE-2019-11477漏洞的利用手段,但是都不够直接,为什么说不够直接呢?因为这些过程往往过于复杂,序列中的每一个步骤都把人搞得晕头转向,但其实这些让人眼花缭乱的东西是可以分离出去的。

本文提供一个干净清爽的方法。不再注入ICMP Need Frag,而是直接将mss协商成48。

先说下这些眼花缭乱的东西包括:

  • 如何诱导被攻击侧增窗并发送18个分散/聚集的整32KB的frag page。
  • 如何中途将mss改成最小值48字节。
  • 如何将raw data的mss凑成8字节。

其中,第一个还是相对容易的,现如今下载服务器发送大文件都是这种方式发送的,你可以试下sendfile系统调用。

第二个前面的文章分散讲过,参见:
CVE-2019-11478 Sack Slowness&Excess Resource Usage漏洞解析与利用
链接是:https://blog.csdn.net/dog250/article/details/94654620
当然,这个条件只是可选,你完全可以一开始建连握手时的SYN报文就把mss协商成48字节,只是需要更大的拥塞窗口罢了,当然这个和SACK Panic本身无关,这是另一个话题,所以本文的假设也就是直接将mss在握手时就协商成48字节。

第三点,也容易,攻击者发送三个空洞数据即可让被攻击者发包时携带3个SACK段,然后加上时间戳和nop对齐,正好占据40字节options,剩余raw data的mss,不多不少,8字节。

好了,我们假设上述三点均已经满足(虽然它们不是那么容易满足,但是请试试看,并不难),这样一来实施漏洞利用就超级简单了。

情况1:发送缓冲区存在一个17个frags组成的大skb的情况

现在,被攻击侧的发送缓冲区为:
在这里插入图片描述

接下来,攻击者构造SACK段:
在这里插入图片描述
此时,一个包含17个frag总长17×3276817\times 32768字节的skb被一次性SACK。

关键是第三步,攻击者再构造一个SACK段:
在这里插入图片描述
其中m1m_1m2m_2m3m_3满足下面的条件时,被攻击侧将gg:

  • m28>65535\dfrac{m_2}{8}>65535
  • m3>0m_3>0m1>0m_1>0
  • m1m_1m2m_2合在一起小于17个frags。

这是因为内核将尝试将长度m2m_2的大skb的一部分和长度为m1m_1的skb进行合并,在合并过程中,在tcp_shift_skb_data中:
在这里插入图片描述

具体调到tcp_shifted_skb内部后,由于pconut参数已经大于了u16所能表示的最大值,就会在u16类型的gso_segs和pcount比较时BUG_ON。


非常清晰的一个过程,现在我们再回过头来反向推敲。

有几个问题:

  • 如何满足17个32KB的frags拼接成一个大的skb?
  • 如何保证大的skb前面有一个小的skb?

其实,上面的条件很难直接被满足,为什么呢?

如果我们看tcp_write_xmit这个正规的TCP发送函数,会发现几乎很难会让一个拥有17×327688\dfrac{17\times 32768}{8}个segs的skb一次被GSO发送出去,拥有各种限制,最终可能会调用tso_fragment将系统调用送来的满足攻击条件的大skb拆分成小的。我们看到,这个还和计算出来的pacing rate有关。

当然了,如果恰好有个服务器参数正好满足攻击条件,那太好不过了,如果不呢?

于是,我们可以换一种思路来间接满足。请问,我有说上面第一幅图的理想发送队列是被攻击侧自己形成的吗?没有啊!其实它也是被诱导形成的啊。

换句话说,即便诸多个skb是被拆分成小skb后一个个发出去的,我也能想办法将其合并成一个大的,就用SACK段合并的原理呗。

那就好办了,我们假设skb都是通过tso_fragment发送出去的,那又如何?注意到tso_fragment函数里只是split了一个skb,移动了frag page的position,offset指针而已,并没有拷贝数据到线性区域:
在这里插入图片描述

这意味着,分散聚集的frag page组成的skb是可以被重新合并起来的。

现在,我补上上文第一幅图之前的图。首先是初始,当拥塞窗口cwnd满足了攻击条件,即inflight字节至少为(17+2)×32768(17+2)\times 32768字节时的情景。
在这里插入图片描述

之所以要+2,是因为一个skb作为una,憋住发送队列,另一个用来做最后的合并,见前文。

接下来先来一波SACK,让从第三个开始的skb合并成一个:
在这里插入图片描述在合并的过程中,gso_segs字段就已经溢出了,但这个方法中,我们不关注它的溢出,我只需要知道它不会超过65535即可,后面的BUG_ON来自于最后一个合并时,tcp_shifted_skb的参数pcount的值大于65535。注意pcount可是个int型哦,这是关键!

OK,这便和第一幅图接上了。


现在,我要吐槽下我自己几天前的方法了。简直太复杂了。简直就是炫技:

  • 中间半途中塞入ICMP Need Frag后超时二分递减mss到达48。
  • 为了重传重新SACK,竟然构建SACK reneg以便超时后全部Mark lost。
  • 两次利用tcp_fragment来重新计算gso_segs,第一次溢出,第二次BUG。

本文的方法超级清爽,并没有直接让gso_segs溢出,而是让len8\dfrac{len}{8}超过65535字节,这办法好。


浙江温州皮鞋湿,下雨进水不会胖。

展开阅读全文

linux内核panic了,

03-08

request irq num 147 <1>CPU 0 Unable to handle kernel paging request at virtual address 00000000, epc == 80269594, ra == 80141960rnOops in arch/mips/mm/fault.c::do_page_fault, line 166[#1]:rnCpu 0rn$ 0 : 00000000 1000c001 ffffffff 00000004rn$ 4 : 00000000 81fe4000 803bbe08 b8038030rn$ 8 : 803d0000 00000000 1000c000 00000000rn$12 : fffffff9 00000000 00000003 00000002rn$16 : 803a945c 00000003 a0000000 00000000rn$20 : 803bbe08 00000093 55aa7788 00000000rn$24 : 00000002 00000000 rn$28 : 803ba000 803bbd50 803a9450 80141960rnHi : 00000083rnLo : e42b2000rnepc : 80269594 Not taintedrnra : 80141960 Status: 1000c003 KERNEL EXL IE rnCause : 10800008rnBadVA : 00000000rnPrId : 0001800arnProcess swapper (pid: 1, threadinfo=803ba000, task=81ff7b48)rnStack : 81ffe1c0 000000d0 801008dc 803c4218 00000000 80350000 00000056 00000056rn ffffffff 00000005 803a9720 803a9720 81fe0f68 00000000 00000001 00000000rn 80141960 ffffffff 00000010 00000004 0000270f 00060000 80365260 00000093rn 81fe0f68 803bbe08 fffffffb 803447d0 80141b0c 80141ac8 803a1993 00000037rn 803ba000 803bbdf8 80365260 1000c001 81fe0f68 00000093 00000000 80100be8rn ...rnCall Trace: [<801008dc>] [<80141960>] [<80141b0c>] [<80141ac8>] [<80100be8>] [<802739f4>] [<801008ec>] [<8012c370>] [<8010b638>] [<8024da10>] [<80141ed0>] [<80141ee8>] [<80152b48>] [<801262f0>] [<80126180>] [<80269518>] [<80142110>] [<8026a398>] [<8026a334>] [<8037e8e0>] [<80366a20>] [<80366a20>] [<803822b8>] [<80376180>] [<80366b10>] [<801004c0>] [<801078c0>] [<801078b0>] rnrnCode: 00000000 8d040038 8d0d00a0 <8c820000> 25af0008 afa20010 8c830004 01af282b afa30014 rnKernel panic - not syncing: Aiee, killing interrupt handler!rnrn有那位大侠说说上面的信息都是什么啊?rn怎么能看出来是再那个代码出的错? 论坛

没有更多推荐了,返回首页