利用AS_PATH Prepend达成SONIC BGP协议DOS案例复现
SONiC是一个面向一个开源的交换机操作系统,Software for Open Networking in the Cloud,简称SONiC。GitHub Repo:https://github.com/Azure/SONiC
本文基于SONIC202012,从搭建环境开始,讲解BGP协议DOS攻击的复现,使用gdb调试工具结合到代码和原理对漏洞的原因进行分析。
使用KVM+ONIE承载SONiC
SONiC是构建网络设备(如交换机)所需功能的软件集合,它必须要有Base OS才能运行,我们用ONIE来承载SONIC。
一开始尝试手动搭建的构建方法,发现各种库没装,装好了编译途中坎坷不断,后来发现官方提供了安装好各种编译环境的容器:https://github.com/opencomputeproject/onie/tree/2021.05-rc1/contrib/build-env
用Docker进行快速编译ONIE
先克隆ONIE的Repo,切换到容器目录,然后安装docker,构建容器
|
|

到了这里,镜像就建好了,用下列命令进入容器
|
|

如果期望分区表为MBR,则需在machine/kvm_x86_64/machine.make把
PARTITION_TYPE改成msdos,默认情况下是gpt,有镜像上云的需求需要在这里修改分区表
然后开始编译
|
|

进行到一半了

镜像编译完成

看一下生成好的镜像

退出容器,打个包下载下来
|
|
安装SONiC到ONIE
文件下载:
- 从Jenkins上可以下载到sonic-vs.bin:sonic-vs.bin
- OVMF.fd (boot=uefi时必须)
参考文档:
目录结构组织参考

步骤开始:
下载 mk-vm.sh
创建空的磁盘镜像:
|
|
按目录结构配置mk-vm.sh的CDROM,DISK,OVMF,然后mode先指定成cdrom,boot必须指定bios,内存必须4096。运行./mk-vm.sh(图中指定了boot=ueif、内存2048,导致后续安装失败,已更正)
- 内存
2048失败的原因:启动ONIE时/tmp分区的大小与内存有关,需要有充足的空间供SONIC镜像存放并解包安装 boot=uefi时失败的原因:在grub-install的时候卡住,根本原因和SecureBoot有关,参见Issue)

启动后马上进onie-embed自动开始安装onie,没进成功进了recovery,想要回到grub请reboot

CTRL + SHIFT + ] 可以退出KVM,回到telnet敲quit退出到终端,退出时会有提示可以使用sudo kill $kvm_pid杀死KVM进程
装完后有sonic-vs.bin的目录下,宿主机起一个httpserver
|
|

rescue模式进入ONIE,onie-nos-install http://虚拟机内网IP/sonic-vs.bin

选择SONIC启动项

过一会就进系统了!!

默认用户名密码:admin/YourPaSsWoRd

附加部分:从制作镜像到上云
为什么要上云? 制作好了镜像,在云上可以直接登录云服务器进行操作,无需复杂的环境配置,等于是开箱即用
这里以腾讯云为平台,进行了SONiC镜像上云的实践。
首先,根据腾讯云文档导入镜像一节的要求,分区表类型不支持GPT,所以我们:
- 重新编译了一个分区类型为MSDOS的镜像,修改
build-config/arch/x86_64.make找到里面的PARTITION_TYPE改成msdos后按原来的样子重新编译 - 并在用
qemu-img创建磁盘镜像时,指定磁盘大小40G

- 进入装好的SONIC,参照腾讯云文档,按照要求:先检查
VirtIO驱动:https://cloud.tencent.com/document/product/213/9929然后安装CloudInit组件:https://cloud.tencent.com/document/product/213/12587其中在执行pip install -r requirements.txt时需要sudo并且把pip改为pip2 - 装好组件后,上传到腾讯云COS存储桶中

- 导入镜像

- 直接从镜像创建云服务器

- 登录云服务器

二、DOS案例复现
交换机vtysh常用命令:
?查帮助- 用
no开头的命令,比如no ip addr 180.0.3.1/24可以对相关命令取反向的效果 - 在进入
config时,do XXX(xxx是show开头的查询类命令)可以查看结果 show ip route查看路由表show interfaces查看所有接口show ip bgp summary查看bgp摘要show ip bgp neighbors查看所有bgp的邻居
云服务器资产:

进行下列配置之前,先在VPC上配置路由表,并把路由表应用到两台SONIC所在的子网


具体配置一览如下
| 标识 | 内网IP | Ethernet8 IP |
|---|---|---|
| SONIC1 | 172.17.16.17/20 | 192.168.3.1/24 |
| SONIC2 | 172.17.16.9/20 | 192.168.3.2/24 |
网络拓扑
SONIC1
|
|
SONIC2
|
|
进行上述配置之后,进行验证,应确保如下所示的条件,才可进行下一步:
- SONIC1可以通过
192.168.3.2到达通SONIC2 - SONIC2可以通过
192.168.3.1到达通SONIC1 - SONIC1/2互相可以获取到对方的
ROUTER ID
具体说明:
以SONIC1为例,执行了ping 192.168.3.2和show ip bgp neighbors进行结果验证:
- 首先,ping结果正常,如果ping都不通更别想玩bgp了
- 且bgp邻居的截图中,
remote router ID不为0.0.0.0,local router ID是刚刚配置的192.168.3.1自己的IP,并且状态为已建立连接:BGP state = Established

信息统计中不全为0,有收发记录

漏洞复现
先在SONIC1进行配置
|
|
然后在SONIC2配置
|
|
敲完最后一句后,过一会SONIC1的终端就有bgpd服务掉线的反馈信息

在SONIC1敲docker logs bgp,可以在日志里看见bgpd非正常退出了

原因挖掘
bgpd的可执行文件在docker-fpm-frr(Name: bgp)的/usr/lib/frr/bgpd
进入bgp容器,gdb attach上bgpd进程,然后敲个c让他继续执行代码
|
|
等coredump的时候,gdb会自动断下来,显示代码停在了bgpd/bgp_aspath.c:2053函数是aspath_cmp

layout asm可以看汇编

经过比较,所示汇编代码对应即为该文件的2053行,https://github.com/Azure/sonic-frr/blob/df7ab485bde1a511f131f7ad6b70cb43c48c8e6d/bgpd/bgp_aspath.c#L2053

gdb里bt,看一下trace,调用aspath_cmp()函数的时候,第一个参数是0x0,bug找到了:aspath_cmp()没有对传来的参数进行空指针判断

有了源码分析,我们知道关于BGP Prepend,是有一个BGP Prepend Hijacking的安全问题,意思是攻击者可以利用Prepend来修改AS_PATH控制流向目标网络的流量。
在回到我们刚才的配置:
- SONIC1聚合20.0.0.0/24的路由,在路径上进行prepend,把
AS1~5都加入到了路径的左侧,这样去往AS65100的流量,都必然经过AS1~5 - SONIC2对20.0.0.1/31和20.0.0.1/31进行了发布,SONIC1收到了发布的流量,聚合操作的设定把20.0.0.1/31和20.0.0.1/31加入到自己的Summary里,但是在聚合的时候,需要确定Next Hop,而
AS1在网络拓扑中根本不存在,聚合操作找不到这个AS号,所以就崩溃了
在如上所示的场景中,是SONIC进行了Prepend修改AS_PATH,倘若是攻击者实施的AS_PATH Prepend,攻击者的目的就达成了——利用Prepend把不存在的AS加入BGP网络达成DOS攻击。
总结
BGP导致的大型安全事件数不胜数,被劫持网络流量、引起大规模的网络故障,大多数都是基于BGP协议的传播性,由单点扩散到全局。对漏洞的深入探究和其他BGP协议的漏洞,可以参照KCon2018的议题《BGP安全之殇》。
文章是根据学校实验课程的大作业实践经历改编,作者自己也是在作业的引导之下,第一次研究关于BGP协议方面的漏洞,上文理解和描述可能存在略有不足之处,欢迎大佬们斧正指出错误。