
Exploit de prova de conceito para CVE-2023-36664, uma vulnerabilidade de injeção de comando no Ghostscript. Inclui ambiente de laboratório Docker, análise detalhada da bypass de validação de pipe e guia de reprodução passo a passo.
CVE ID: CVE-2023-36664
Produto: Ghostscript (< 10.01.2)
Tipo de Vulnerabilidade: Execução Remota de Código (RCE)
Esta vulnerabilidade (CVE-2023-36664) é uma falha de Execução Remota de Código (RCE) que ocorre devido ao tratamento inadequado da validação de permissões de caminho para dispositivos pipe (%pipe% ou prefixo |) pelo Ghostscript.
Durante a análise ou processamento de um arquivo de documento (PS/EPS) maliciosamente manipulado por um atacante, comandos arbitrários do sistema podem ser executados sem autorização do usuário.
Função principal: Ele lê códigos de coordenadas gráficas essencialmente compostos por texto (por exemplo, "desenhe uma linha na posição 100 200") e os converte em imagens que podem ser exibidas em monitores ou impressas.
Um pipe é um recurso que conecta a saída de uma aplicação à entrada de outra, permitindo que softwares se comuniquem entre si. Em comandos, é representado pelo símbolo |.
Exemplo: cat /etc/hosts | grep localhost
O Ghostscript, quando o modo seguro (-dSAFER) está ativado por padrão, verifica rigorosamente os caminhos de arquivos para evitar acesso a arquivos sensíveis do sistema ou execução arbitrária de comandos externos.
Problema: Quando um atacante insere astuciosamente um prefixo de dispositivo pipe (%pipe% ou |) no lugar de um nome de arquivo comum, a lógica interna de validação de permissões do Ghostscript não reconhece corretamente esse prefixo, confundindo-o com um "caminho seguro" ou "algo que não precisa ser verificado", permitindo sua passagem.
Resultado: Comandos perigosos que deveriam ter sido filtrados acabam contornando o loop de validação trivialmente.
Injeção de arquivos maliciosos: O atacante insere código dentro de um arquivo PostScript (.ps/.eps) no formato (%pipe%comando_malicioso) (modo) file /DCTDecode filter.
Parsing e engano: Durante a leitura e processamento deste arquivo, o Ghostscript passa pela etapa de validação de permissões (porteiro) sem erros.
Encaminhamento para o shell do SO: O fluxo de comandos que passou pela validação é então transmitido, pela funcionalidade do dispositivo pipe, diretamente para o shell interno do sistema operacional, como sh no Linux ou cmd no Windows, sendo executado com permissões de backend.
Ao observar o código corrigido, vemos que dois arquivos .c foram modificados:
base/gpmisc.cbase/gslibctx.cAqui, examinando gpmisc.c, podemos entender a vulnerabilidade.

O cerne desta vulnerabilidade é que caminhos especiais como %pipe% não são corretamente distinguidos de caminhos de arquivo comuns, sendo tratados como caminhos normais.
gp_file_name_reducePara verificar isso, é necessário examinar a função que limpa o caminho do arquivo. Em gpmisc.c, a função responsável por limpar o caminho é gp_file_name_reduce(...), que internamente chama gp_file_name_combine() e retorna o resultado.
gp_file_name_reduce(const char *fname, uint flen, char *buffer, uint *blen) {
return gp_file_name_combine(fname, flen, fname + flen, 0, false, buffer, blen);
}
gp_file_name_combine(), como o nome indica, é uma função que remove expressões de caminho relativo desnecessárias, como ./ e //, do caminho de arquivo recebido.
O problema ocorre aqui. Se esta função receber não um caminho de arquivo normal, mas uma string especial como %pipe% que visa executar comandos, a função não a reconhece como um padrão de caminho válido e retorna a string original sem qualquer processamento.
gp_validate_path_len
gp_validate_path_len(...) é uma função que internamente chama gp_file_name_reduce() para validar o caminho. No entanto, neste processo, não existe uma lógica de validação separada para distinguir se a entrada é um caminho de arquivo comum ou uma sintaxe de execução de comando como %pipe%.
Consequentemente, strings contendo %pipe% passam sem qualquer filtragem, e essa é a causa raiz desta vulnerabilidade.
Assim, se uma string como %pipe%touch /tmp/pwned for passada como caminho de arquivo, o usuário, que pretendia apenas renderizar um arquivo de imagem, acaba fazendo com que o comando touch /tmp/pwned seja executado, criando o arquivo /tmp/pwned.
┌─────────────────────────────────┐
│ Docker Container │
│ (Ubuntu 22.04 + Ghostscript) │
│ │
│ /home/test/ ← Diretório de trabalho
│ ├── poc.py ← Script de geração do PoC
│ | |
│ └── /var/www/html/config.php ← Arquivo de informações sensíveis
│ │
│ User: test (não root) │
│ Ghostscript: 10.01.1 (vulnerável)│
└─────────────────────────────────┘
A razão para escolher uma conta de usuário comum em vez da conta root é que, em servidores reais, geralmente não se usa diretamente a conta root por questões de segurança. Portanto, para reproduzir o mais fielmente possível uma situação em que um servidor real é atacado, o ambiente foi configurado com base em uma conta de usuário comum.
version: '3.8'
services:
gs-lab:
build: .
container_name: cve_lab
network_mode: "host"
environment:
- DISPLAY=${DISPLAY}
volumes:
- /tmp/.X11-unix:/tmp/.X11-unix:ro
- ./poc.py:/home/test/poc.py
stdin_open: true
tty: true
DISPLAY=${DISPLAY}: Passa a variável de ambiente para que aplicações GUI dentro do contêiner possam acessar o servidor de exibição X11 do host./tmp/.X11-unix:/tmp/.X11-unix:ro: Monta o socket Unix para comunicação entre o servidor de exibição X11 do host e o contêiner.
./poc.py:/home/test/poc.py: Monta o script PoC local do host no ambiente de execução do contêiner.
FROM ubuntu:22.04
RUN apt update && \
apt install -y \
wget \
build-essential \
gedit \
python3 \
sudo && \
rm -rf /var/lib/apt/lists/*
RUN wget https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs10011/ghostscript-10.01.1.tar.gz && \
tar -xzf ghostscript-10.01.1.tar.gz
WORKDIR /ghostscript-10.01.1
RUN ./configure && \
make && \
make install
RUN mkdir -p /var/www/html && \
echo "DB_PASSWORD=SuperSecret1234!!!" > /var/www/html/config.php
RUN useradd -m -s /bin/bash test
WORKDIR /home/test
USER test
CMD ["/bin/bash"]
Para configurar o ambiente PoC básico, são necessários: wget para baixar a versão vulnerável do Ghostscript, build-essential para instalar a fonte após extrair o tar.gz, e um editor de texto (gedit) para abrir maliciosamente ao executar o .ps.
A versão vulnerável 10.01.1 do Ghostscript foi instalada a partir do código-fonte baixado do git. O comando RUN ./configure && \ make && \ make install foi seguido conforme as instruções de uso na pasta onde o código-fonte foi baixado.
Normalmente, /var/www/html/config.php contém as definições principais de uma aplicação web, como nome do banco de dados e senha. Por isso, assumindo que a senha do banco de dados será roubada, criamos o arquivo config.php com um valor fictício.
Como o PoC será realizado com o usuário comum test, não root, criamos um novo usuário.
# Construir a imagem Docker
docker compose -f docker-compose.yml up -d
# Executar o contêiner
docker exec -it cve_lab bash
Dentro do contêiner:

python3 poc.py -p "gedit /var/www/html/config.php" -m r -f test
Resultado da geração:

Podemos ver que o caminho malicioso inserido está corretamente dentro do arquivo .ps.
gs -dNOSAFER test.ps

O gedit é aberto automaticamente e o conteúdo de /var/www/html/config.php é exibido.
DB_PASSWORD=SuperSecret1234!!!

É necessário atualizar para a versão mais recente do Ghostscript (10.01.2 ou superior) que corrige oficialmente a vulnerabilidade.
No patch oficial, foi adicionada uma lógica de validação dentro da função gp_validate_path_len() antes de chamar gp_file_name_reduce().
Tratamento de exceção e bloqueio forçado para strings pipe especiais: Foi adicionada uma declaração condicional que detecta perfeitamente quando o prefixo do caminho de entrada começa com %pipe% ou o símbolo |.
Versão do patch oficial: https://github.com/ArtifexSoftware/ghostpdl/commit/5f56c6f6f989816fc9cc671116740acecbed5b6c