Por Thiago Escobar

A linguagem de marcação Edge Side Includes permite a criação de uma página a partir de fragmentos. Esses fragmentos são interpretados no servidor de cache e realizam ações no processo de criação da página HTML. A vulnerabilidade ocorre quando é possível injetar esses fragmentos de forma arbitrária.

A descrição acima pode parecer confusa devido à introdução de diversos conceitos. Então, vamos por partes. A tecnologia Edge Side Includes visa otimizar o processo de criação de documentos HTML por meio do uso de servidores de cache. É importante compreender o papel desses servidores para uma melhor compreensão do contexto.

Servidores de cache

Um servidor de cache atua como intermediário na comunicação entre o cliente e o servidor. Quando uma requisição é feita para determinado conteúdo, a resposta é temporariamente armazenada no servidor de cache. Isso significa que, se houver uma nova solicitação para o mesmo conteúdo dentro desse período, não será necessário fazer uma nova requisição ao servidor da aplicação, pois o servidor de cache já possui a resposta. Isso permite entregar o conteúdo mais rapidamente ao usuário final. Além disso, essa abordagem reduz a carga no servidor, uma vez que a demanda por recursos é diminuída, proporcionando uma experiência mais eficiente e ágil para os usuários.

Edge Side Includes

Edge Side Includes (ESI) é uma linguagem de marcação baseada em XML que permite a composição dinâmica de páginas web por meio de diversos fragmentos. Cada fragmento pode ser individualmente armazenado no servidor de cache, contribuindo assim para a eficiência do processo de criação da página. Esses fragmentos são capazes de ser requisitados separadamente ao servidor da aplicação.

A utilização de servidores de cache desempenha um papel crucial nesse contexto, diminuindo o tempo de resposta ao cliente. Ao fazer o uso de elementos ESI, o servidor de cache pode armazenar e servir fragmentos específicos, evitando a necessidade de recarregar a página inteira a cada solicitação. Isso não apenas aprimora a velocidade de carregamento da página para o usuário final, mas, também, reduz a carga sobre os recursos do servidor da aplicação.

Em resumo, Edge Side Includes é uma ferramenta para otimizar a entrega de conteúdo web, permitindo uma abordagem flexível na construção de páginas por meio da gestão de fragmentos e aproveitando os benefícios dos servidores de cache. Abaixo apresenta-se um exemplo prático em Node.js de uma página construída por meio de fragmentos.

A seguir, podemos observar o conteúdo do arquivo esi.html:

É possível observar que a página “esi.html”, enviada como resposta à requisição da página “/esidemo”, incorpora fragmentos ESI. Esses fragmentos são requisitados e inseridos individualmente na página principal. Posteriormente, a página, agora composta por todos os fragmentos, é enviada ao usuário, conforme ilustrado na imagem. Abaixo, é possível analisar mais detalhadamente o fluxo de criação desta página:

Fonte: https://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Edge%20Side%20Include%20Injection%20Abusing%20-%20Dion%20Marcil.pdf

No exemplo anterior, utilizou-se a ação “include”, que efetua uma requisição e insere a resposta na página principal. No entanto, é importante destacar que existem outras ações possíveis, como ilustrado abaixo:

Ações Edge Side Includes

A sintaxe da tecnologia Edge Side Includes segue a seguinte lógica:

“<esi:[ação] atributos=”valor” />”

Dentre as ações possíveis, as mais interessantes para atacar servidores de cache são:

  • Include: Foi a ação ESI usada nos exemplos anteriores, elemento “Include” em ESI é responsável pela formação de páginas através de fragmentos. O servidor de cache, por meio do processador ESI, realiza requisições para buscar atributos e os insere na página principal, antes de enviá-la ao usuário final. Essa ação permite uma montagem dinâmica do conteúdo.
  • Vars:  O elemento vars é o elemento ESI que permite a adição de variáveis. Essas variáveis são interpretadas no servidor de cache. Abaixo estão descritas as possibilidades de variáveis conforme a documentação oficial.
Fonte: https://www.w3.org/TR/esi-lang/

    – inline:  Na documentação do oracle web cache temos a seguinte definição, em tradução livre: “Marca um fragmento como um fragmento armazenável em cache separadamente, incorporado na resposta HTTP de outro objeto”. Na prática, esse elemento permite a sobrescrita de uma entrada por um dado arbitrário (ilustrado com mais detalhes nos ataques usando ESI Injection).

Obs: No texto acima, foram descritas as ações mais cruciais para compreender a vulnerabilidade Edge Side Include Injection, tomando como base a documentação oficial. É importante destacar que cada servidor de cache possui um conjunto específico de tags que podem ser interpretadas. Além disso, alguns servidores podem implementar suas próprias tags ESI, ampliando as possibilidades.

Edge Side Include Injection

A vulnerabilidade de e Edge Side Include Injection ocorre quando um atacante consegue inserir tags ESI arbitrárias para serem interpretadas no servidor de cache. As possibilidades de ataque variam dependendo do servidor de cache alvo e de sua configuração específica.

Alguns servidores de cache, como o Varnish Cache, podem apresentar limitações significativas. No caso do Varnish, ele aceita apenas três ações ESI. Por outro lado, servidores como o Oracle Web Cache têm a capacidade de interpretar toda a documentação oficial e ainda adicionam suas próprias ações ESI.

Durante o estudo sobre ESI, a maioria dos laboratórios de estudos foram conduzidos utilizando o Apache Traffic Server. Esse servidor aceita todos os elementos descritos na documentação oficial da tecnologia com exceção de alguns tópicos específicos:

  • A ação “include” não oferece suporte aos atributos “alt” e “onerror”
  • A ação “inline” não é suportada, o que significa que não existe a sobrescrita de arquivos citada anteriormente
  • O “HTTP_COOKIE” não é suportado como variável ESI
  • O “HTTP_USER_AGENT” não é suportado como variável ESI, embora seja possível retornar o User-Agent conforme será mostrado posteriormente
  • Embora o “HTTP_HEADER” permita acessar headers da requisição como variáveis, não é possível recuperar a variável “Cookie” devido à falta de suporte

Exemplo Prático
Nesse exemplo, temos uma aplicação de postagens, onde o post realizado na página principal é refletido na página de posts, conforme ilustrado abaixo:

Agora que sabemos que a aplicação reflete os valores inseridos, vamos realizar o teste utilizando um payload que se baseia na injeção HTML da tag “<img>”. Neste caso, o payload, inicialmente interpreta o elemento ESI e em seguida faz uma requisição para o servidor de controle do atacante, contendo o User-Agent da vítima (valor correspondente à variável ESI interpretada anteriormente), conforme ilustrado abaixo:

Obs: esse payload necessita que a aplicação também seja vulnerável a XSS para mostrar a ideia de que JavaScript ajuda em ataques de ESI Injection (mas não é necessário conforme será mostrado em exemplos posteriores)

Exemplo Prático em APIs

No exemplo anterior do cenário web, ficou evidente que para realizar a injeção da tag ESI é necessário inserir os caracteres ‘<‘ e ‘>’, uma vez que a sintaxe dessa tecnologia segue esse padrão. No entanto, é importante observar que alguns firewalls e implementações de segurança podem bloquear esse tipo de caractere, pois são interpretados como potenciais ataques de XSS (Cross-Site Scripting) ou Injeção de HTML. Em cenários envolvendo APIs, é menos comum encontrar verificações desse tipo, uma vez que o conteúdo não será interpretado diretamente no navegador, mas sim exibido para o usuário. Contudo, mesmo no cenário supracitado, ainda é possível observar a ocorrência de injeção de ESI. Na imagem abaixo podemos observar o funcionamento normal de uma API que retorna as capitais e seu estado a partir de um país informado no campo ‘lugar’:

Em casos de inserção de um lugar inválido, é possível observar que o valor do parâmetro “lugar” é refletido na resposta e a mensagem a seguir é retornada pela API:

Ao efetuar a injeção da tag ESI no parâmetro refletido, foi possível retornar o header solicitado na variável ESI, conforme ilustrado abaixo:

Ataques

Os exemplos anteriores abordaram, principalmente, injeções de tags ESI simples onde o atacante pega informações não sensíveis. No entanto, é importante ressaltar a vasta gama de possibilidades que essa vulnerabilidade pode oferecer. Edge Side Include Injection pode abrir portas para ataques mais críticos, como sequestro de sessão, negação de serviço (Denial of Service), Server-Side Request Forgery, entre outros. Vale ressaltar que a extensão desses ataques dependerá fortemente da configuração específica do servidor de cache.

Session Hijacking

Nesse artigo vamos explorar duas possibilidades de session hijacking, usando o elemento vars para pegar os headers “Cookie” e “Authorization” e usando a sobrescrita de arquivos do “inline”

1 – Informações nos Headers

As informações presentes nos headers podem variar em cada aplicação testada. Nos casos em que informações sensíveis são encontradas nos headers, podemos utilizar a variável ESI para retornar esses dados. No exemplo abaixo, foi possível recuperar o Authorization header, associado a um Token de sessão. De maneira semelhante ao exemplo utilizado na API, observamos que o parâmetro ‘evento’ está sendo refletido na resposta. Isso significa que é possível realizar a injeção ESI e retornar o Header desejado conforme ilustrado abaixo:

Para recuperar o cabeçalho “Cookie”, o processo segue uma abordagem semelhante ao exemplo anterior. No entanto, no caso específico do Apache Traffic Server, utilizado nos exemplos, esse tipo de ataque não é viável, conforme descrito na documentação.

É interessante ressaltar que, no contexto dos Cookies, mesmo com a flag “HttpOnly” habilitada, ainda é possível obter os cookies de sessão. Isso ocorre devido ao fato de que eles não estão sendo recuperados através da execução de JavaScript e, sim, através do interpretador ESI ao substituir o “esi:vars” pelo valor solicitado.

2 – Inline

Como destacado no início deste artigo, a capacidade de sobrescrita de arquivos é permitida pela ação ‘inline’. Vamos considerar um cenário em que uma aplicação solicita o arquivo ‘tempest.js’ em diversos pontos. Ao utilizar o “inline”, torna-se possível sobrescrever esse arquivo, transformando todos os pontos em que ele é solicitado em potenciais pontos de ataque. Um exemplo de payload ilustrativo é apresentado abaixo:

O ataque em questão consiste em sobrescrever o arquivo Javascript solicitado, nesse caso, o ‘tempest.js’, com o conteúdo observado na imagem acima. Este trecho de código apresenta um comportamento semelhante ao descrito no exemplo do Apache Traffic Server, onde ocorre a substituição da variável ESI pelo header solicitado, e por último é feita uma requisição para o ‘evil.com’.

Obs: Este exemplo, assim como o do Apache Traffic Server, utiliza recursos possíveis apenas no cenário web, aproveitando a execução de JavaScript a nosso favor.

Server-side Request Forgery (SSRF)

Vamos explorar duas formas de realizar um ataque de SSRF. A primeira envolve o uso do include com um fragmento externo, e também discutiremos a CVE-2019-2438. Entretanto, o primeiro cenário é pouco comum, uma vez que, na grande maioria dos casos, as requisições são direcionadas apenas a hosts presentes em uma allowlist.

1 – Include com um fragmento externo

Esse primeiro cenário é o mais intuitivo, pois captura a ideia geral do ESI Include ao simplesmente adicionar a origem externa para aquele fragmento. Dessa forma, o fluxo da injeção é segue a linha descrita abaixo:

Como mencionado anteriormente, o servidor de cache ao interpretar o elemento ESI include inserido nesse trecho fará a requisição para o evil.com. Para melhor entendimento da vulnerabilidade, recomendo a leitura https://www.sidechannel.blog/server-side-request-forgery-ataque-e-defesa/ 

CVE-2019-2438 (SSRF Limitado)

No segundo caso, tratamos de uma das implementações específicas destacadas no início do artigo, onde o servidor de cache Oracle Web Cache, na versão 11.1.1.9.0, possibilita a inclusão de cabeçalhos na requisição realizada pelo elemento “include” através do elemento “request_header”, um payload de exemplo está ilustrado abaixo:

Quando o header personalizado é adicionado, ele é incorporado na primeira linha após a request line. Desta maneira, é possível adicionar um novo header “host”, o comportamento nesse cenário é descrito no seguinte artigo:https://www.icir.org/vern/papers/host-of-troubles.ccs16.pdf“, conforme observado no artigo citado em alguns cenários a requisição será bem sucedida e o primeiro host será considerado.

Denial of Service (CVE-2018-1000024 e CVE-2018-1000027)

Ambas as CVEs afetam o servidor de cache Squid em versões antes da 4.0.23, ambas são relacionadas a erros de ponteiro. Em programação, um ponteiro é uma variável que armazena o endereço de memória de outra variável. Ele fornece um meio de acessar e manipular dados diretamente na memória.

CVE-2018-1000024 – Incorrect Pointer Handling vulnerability (CVSS 7.4)

A vulnerabilidade de Manipulação Incorreta de Ponteiro no Processamento de Respostas ESI pode resultar em Negação de Serviço para todos os clientes que utilizam o proxy. O ataque pode ocorrer quando um servidor remoto entrega uma resposta HTTP com uma sintaxe ESI válida, porém incomum.

CVE-2018-1000027 – NULL Pointer Dereference vulnerability (CVSS 6.8)

A vulnerabilidade de Desreferência de Ponteiro Nulo, assim como a vulnerabilidade descrita acima, pode causar negação de serviço para todos os clientes que utilizam o proxy, nesse caso o problema ocorre no processamento do cabeçalho de Resposta HTTP X-Forwarded-For. Este ataque parece ser explorável por meio de um servidor HTTP remoto que responde com um cabeçalho X-Forwarded-For a certos tipos de solicitações HTTP

Detecção

Para realizar a detecção da vulnerabilidade deve-se procurar informações que indiquem o uso dessa tecnologia como headers de servidores de cache que aceitam o uso de ESI ou de forma mais ativa através da injecção de tags ESI, nesse segundo caso é recomendado testes usando o elemento “<!– esi–>” já que é interpretado na grande maioria dos servidores de cache (se não todos).

No exemplo abaixo, é possível observar que, de maneira semelhante ao cenário previamente ilustrado, esta API reflete o valor inserido quando não é encontrado. Assim, é possível verificar a possibilidade de injeção ESI por meio do elemento mencionado anteriormente. As imagens a seguir ilustram o fato.

Como é possível observar na segunda imagem, o elemento ESI foi interpretado no servidor de cache, resultando na saída ‘foobar’ para o usuário. 

No contexto de uma API, este teste é bastante simples. No entanto, no cenário web, o elemento ESI assemelha-se a um comentário HTML. Para a demonstração, utilizaremos o mesmo laboratório anteriormente empregado no cenário web, a fim de ilustrar um cenário de detecção nesse contexto. Abaixo é possível visualizar os envios arbitrários de um atacante tendo inicialmente um elemento ESI e em seguida um comentário HTML.

Abaixo é possível observar o inspecionar código HTML enviado para o usuário

Como é possível observar, o comentário HTML ainda está presente no código-fonte HTML da página, enquanto o elemento ESI foi interpretado e, posteriormente, enviado ao usuário final. Em outras palavras, para o usuário final, não há qualquer indicação da presença desse elemento na página.

Dessa forma é possível confirmar que está sendo possível interpretar a tag ESI no servidor de cache, é possível também testar por tags específicas, porém existe a possibilidade do servidor de cache estudado não aceitar a ação desejada e resultar em um falso negativo.

Correção/Mitigação

A vulnerabilidade de ESI injection surge principalmente de configurações inadequadas nos servidores de cache. Portanto, é crucial sua configuração de forma correta. Além disso, Edge Side Include Injection é uma linguagem de marcação baseada em XML, isso faz com que seja possível sua detecção a partir do OWASP ModSecurity Core Rule Set, que é um conjunto de regras genéricas de detecção de ataques.

A ESI Injection está correlacionada a outras vulnerabilidades, como por exemplo Cross-Site Scripting (XSS) e Server-Side Request Forgery (SSRF). Logo, é importante lidar com essas vulnerabilidades para reduzir o impacto potencial da ESI Injection e seguir boas práticas de segurança, como a atualização regular das tecnologias utilizadas.

Caso Real

Na plataforma HackerOne, um caso real evidencia os riscos de Injeção ESI (Edge Side Includes. O incidente envolveu um ataque de “account takeover” que explorou uma vulnerabilidade de Injeção ESI, permitindo a extração de cookies de sessão através do seguinte payload ‘<esi:vars>$(HTTP_HEADER{Cookie})</esi:vars>’. Além disso, uma vulnerabilidade de XSS Refletido contribuiu para o roubo de cookies. A combinação dessas falhas permitiu aos atacantes realizar “account takeover” e comprometer a segurança da plataforma, assim como mencionado durante esse artigo, o Javascript ajuda em ataques envolvendo ESI. Detalhes completos do incidente e ações corretivas podem ser encontrados no relatório HackerOne, através do link: https://hackerone.com/reports/1073780.

Referências

2018 Beyond XSS: Edge Side Include Injection. Disponivel em: <https://gosecure.ai/blog/2018/04/03/beyond-xss-edge-side-include-injection/>

2019 ESI Injection Part 2: Abusing specific implementations. Disponível em: <https://gosecure.ai/blog/2019/05/02/esi-injection-part-2-abusing-specific-implementations/>

Apache Traffic Server ESI Plugin. Disponível em: <https://docs.trafficserver.apache.org/admin-guide/plugins/esi.en.html>

ESI Language Specification 1.0. Disponível em: <https://www.w3.org/TR/esi-lang/>

ESI Injection paper publicado durante a black hat USA 2018 .Disponível em: <https://i.blackhat.com/us-18/Wed-August-8/us-18-Dion_Marcil-Edge-Side-Include-Injection-Abusing-Caching-Servers-into-SSRF-and-Transparent-Session-Hijacking-wp.pdf>