CSS Injection
Last updated
Last updated
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Os seletores CSS são elaborados para corresponder aos valores dos atributos name
e value
de um elemento input
. Se o atributo value do elemento de entrada começar com um caractere específico, um recurso externo pré-definido é carregado:
No entanto, essa abordagem enfrenta uma limitação ao lidar com elementos de entrada ocultos (type="hidden"
) porque elementos ocultos não carregam fundos.
Para contornar essa limitação, você pode direcionar um elemento irmão subsequente usando o combinador de irmãos gerais ~
. A regra CSS então se aplica a todos os irmãos que seguem o elemento de entrada oculto, fazendo com que a imagem de fundo seja carregada:
Um exemplo prático de exploração dessa técnica é detalhado no trecho de código fornecido. Você pode visualizá-lo aqui.
Para que a técnica de Injeção de CSS seja eficaz, certas condições devem ser atendidas:
Comprimento do Payload: O vetor de injeção de CSS deve suportar payloads suficientemente longos para acomodar os seletores elaborados.
Reavaliação de CSS: Você deve ter a capacidade de emoldurar a página, o que é necessário para acionar a reavaliação do CSS com payloads recém-gerados.
Recursos Externos: A técnica assume a capacidade de usar imagens hospedadas externamente. Isso pode ser restrito pela Política de Segurança de Conteúdo (CSP) do site.
Como explicado neste post, é possível combinar os seletores :has
e :not
para identificar conteúdo mesmo de elementos cegos. Isso é muito útil quando você não tem ideia do que está dentro da página da web que carrega a injeção de CSS.
Também é possível usar esses seletores para extrair informações de vários blocos do mesmo tipo, como em:
Combinando isso com a seguinte técnica de @import, é possível exfiltrar uma grande quantidade de info usando injeção de CSS de páginas cegas com blind-css-exfiltration.
A técnica anterior tem algumas desvantagens, verifique os pré-requisitos. Você precisa ser capaz de enviar múltiplos links para a vítima, ou precisa ser capaz de iframe a página vulnerável à injeção de CSS.
No entanto, há outra técnica inteligente que usa CSS @import
para melhorar a qualidade da técnica.
Isso foi mostrado pela primeira vez por Pepe Vila e funciona assim:
Em vez de carregar a mesma página repetidamente com dezenas de diferentes payloads a cada vez (como na anterior), vamos carregar a página apenas uma vez e apenas com um import para o servidor do atacante (este é o payload a ser enviado para a vítima):
A importação vai receber algum script CSS dos atacantes e o navegador irá carregá-lo.
A primeira parte do script CSS que o atacante enviará é outra @import
para o servidor dos atacantes novamente.
O servidor dos atacantes não responderá a esta solicitação ainda, pois queremos vazar alguns caracteres e então responder a esta importação com a carga útil para vazar os próximos.
A segunda e maior parte da carga útil será um payload de vazamento de seletor de atributo
Isso enviará ao servidor dos atacantes o primeiro caractere do segredo e o último
Uma vez que o servidor dos atacantes tenha recebido o primeiro e o último caractere do segredo, ele responderá à importação solicitada no passo 2.
A resposta será exatamente a mesma que os passos 2, 3 e 4, mas desta vez tentará encontrar o segundo caractere do segredo e depois o penúltimo.
O atacante seguirá esse loop até conseguir vazar completamente o segredo.
Você pode encontrar o código original de Pepe Vila para explorar isso aqui ou você pode encontrar quase o mesmo código, mas comentado aqui.
O script tentará descobrir 2 caracteres a cada vez (do início e do fim) porque o seletor de atributo permite fazer coisas como:
Isso permite que o script vaze o segredo mais rápido.
Às vezes, o script não detecta corretamente que o prefixo + sufixo descoberto já é a flag completa e continuará avançando (no prefixo) e retrocedendo (no sufixo) e em algum momento ficará travado. Sem preocupações, apenas verifique a saída porque você pode ver a flag lá.
Outras maneiras de acessar partes do DOM com seletores CSS:
.class-to-search:nth-child(2)
: Isso irá buscar o segundo item com a classe "class-to-search" no DOM.
:empty
seletor: Usado por exemplo em este writeup:
Referência: Ataque baseado em CSS: Abusando unicode-range de @font-face , PoC XS-Search baseado em erro por @terjanq
A intenção geral é usar uma fonte personalizada de um endpoint controlado e garantir que o texto (neste caso, 'A') seja exibido com essa fonte apenas se o recurso especificado (favicon.ico
) não puder ser carregado.
Uso de Fonte Personalizada:
Uma fonte personalizada é definida usando a regra @font-face
dentro de uma tag <style>
na seção <head>
.
A fonte é nomeada poc
e é buscada de um endpoint externo (http://attacker.com/?leak
).
A propriedade unicode-range
é definida como U+0041
, direcionando o caractere Unicode específico 'A'.
Elemento Object com Texto de Reposição:
Um elemento <object>
com id="poc0"
é criado na seção <body>
. Este elemento tenta carregar um recurso de http://192.168.0.1/favicon.ico
.
A font-family
para este elemento é definida como 'poc'
, conforme definido na seção <style>
.
Se o recurso (favicon.ico
) falhar ao carregar, o conteúdo de reposição (a letra 'A') dentro da tag <object>
é exibido.
O conteúdo de reposição ('A') será renderizado usando a fonte personalizada poc
se o recurso externo não puder ser carregado.
A :target
pseudo-classe é empregada para selecionar um elemento direcionado por um fragmento de URL, conforme especificado na especificação de Seletores CSS Nível 4. É crucial entender que ::target-text
não corresponde a nenhum elemento a menos que o texto seja explicitamente direcionado pelo fragmento.
Uma preocupação de segurança surge quando atacantes exploram o recurso Scroll-to-text, permitindo que confirmem a presença de texto específico em uma página da web ao carregar um recurso de seu servidor através da injeção de HTML. O método envolve injetar uma regra CSS como esta:
Em tais cenários, se o texto "Administrator" estiver presente na página, o recurso target.png
é solicitado ao servidor, indicando a presença do texto. Uma instância deste ataque pode ser executada através de uma URL especialmente elaborada que incorpora o CSS injetado junto com um fragmento Scroll-to-text:
Aqui, o ataque manipula a injeção de HTML para transmitir o código CSS, visando o texto específico "Administrator" através do fragmento Scroll-to-text (#:~:text=Administrator
). Se o texto for encontrado, o recurso indicado é carregado, sinalizando inadvertidamente sua presença para o atacante.
Para mitigação, os seguintes pontos devem ser observados:
Correspondência STTF Constrangida: O Fragmento Scroll-to-text (STTF) é projetado para corresponder apenas a palavras ou frases, limitando assim sua capacidade de vazar segredos ou tokens arbitrários.
Restrição a Contextos de Navegação de Nível Superior: O STTF opera exclusivamente em contextos de navegação de nível superior e não funciona dentro de iframes, tornando qualquer tentativa de exploração mais perceptível para o usuário.
Necessidade de Ativação do Usuário: O STTF requer um gesto de ativação do usuário para operar, o que significa que as explorações são viáveis apenas por meio de navegações iniciadas pelo usuário. Esse requisito mitiga consideravelmente o risco de ataques serem automatizados sem interação do usuário. No entanto, o autor do post do blog aponta condições específicas e contornos (por exemplo, engenharia social, interação com extensões de navegador prevalentes) que podem facilitar a automação do ataque.
A conscientização sobre esses mecanismos e vulnerabilidades potenciais é fundamental para manter a segurança na web e proteger contra táticas exploratórias.
Para mais informações, consulte o relatório original: https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/
Você pode conferir um exploit usando esta técnica para um CTF aqui.
Você pode especificar fontes externas para valores unicode específicos que só serão coletados se esses valores unicode estiverem presentes na página. Por exemplo:
Quando você acessa esta página, o Chrome e o Firefox buscam "?A" e "?B" porque o nó de texto de sensitive-information contém os caracteres "A" e "B". Mas o Chrome e o Firefox não buscam "?C" porque não contém "C". Isso significa que conseguimos ler "A" e "B".
Referência: Wykradanie danych w świetnym stylu – czyli jak wykorzystać CSS-y do ataków na webaplikację
A técnica descrita envolve a extração de texto de um nó explorando ligaduras de fonte e monitorando mudanças na largura. O processo envolve várias etapas:
Criação de Fontes Personalizadas:
Fontes SVG são criadas com glifos que têm um atributo horiz-adv-x
, que define uma largura grande para um glifo representando uma sequência de dois caracteres.
Exemplo de glifo SVG: <glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>
, onde "XY" denota uma sequência de dois caracteres.
Essas fontes são então convertidas para o formato woff usando fontforge.
Detecção de Mudanças de Largura:
CSS é usado para garantir que o texto não quebre (white-space: nowrap
) e para personalizar o estilo da barra de rolagem.
A aparição de uma barra de rolagem horizontal, estilizada de forma distinta, atua como um indicador (oráculo) de que uma ligadura específica, e portanto uma sequência de caracteres específica, está presente no texto.
O CSS envolvido:
Processo de Exploração:
Passo 1: Fontes são criadas para pares de caracteres com largura substancial.
Passo 2: Um truque baseado em barra de rolagem é empregado para detectar quando o glifo de grande largura (ligadura para um par de caracteres) é renderizado, indicando a presença da sequência de caracteres.
Passo 3: Ao detectar uma ligadura, novos glifos representando sequências de três caracteres são gerados, incorporando o par detectado e adicionando um caractere anterior ou posterior.
Passo 4: A detecção da ligadura de três caracteres é realizada.
Passo 5: O processo se repete, revelando progressivamente todo o texto.
Otimização:
O método de inicialização atual usando <meta refresh=...
não é ideal.
Uma abordagem mais eficiente poderia envolver o truque CSS @import
, melhorando o desempenho da exploração.
Referência: PoC usando Comic Sans por @Cgvwzq & @Terjanq
Esse truque foi lançado neste thread do Slackers. O charset usado em um nó de texto pode ser vazado usando as fontes padrão instaladas no navegador: não são necessárias fontes externas -ou personalizadas-.
O conceito gira em torno da utilização de uma animação para expandir gradualmente a largura de um div
, permitindo que um caractere de cada vez transite da parte 'sufixo' do texto para a parte 'prefixo'. Esse processo efetivamente divide o texto em duas seções:
Prefixo: A linha inicial.
Sufixo: A(s) linha(s) subsequente(s).
As etapas de transição dos caracteres apareceriam da seguinte forma:
C ADB
CA DB
CAD B
CADB
Durante essa transição, o truque unicode-range é empregado para identificar cada novo caractere à medida que se junta ao prefixo. Isso é alcançado mudando a fonte para Comic Sans, que é notavelmente mais alta do que a fonte padrão, acionando assim uma barra de rolagem vertical. A aparição dessa barra de rolagem revela indiretamente a presença de um novo caractere no prefixo.
Embora esse método permita a detecção de caracteres únicos à medida que aparecem, não especifica qual caractere está sendo repetido, apenas que uma repetição ocorreu.
Basicamente, o unicode-range é usado para detectar um char, mas como não queremos carregar uma fonte externa, precisamos encontrar outra maneira. Quando o char é encontrado, ele é dado a fonte Comic Sans pré-instalada, que torna o char maior e aciona uma barra de rolagem que irá vazar o char encontrado.
Verifique o código extraído do PoC:
Referência: Isso é mencionado como uma solução malsucedida neste relatório
Este caso é muito semelhante ao anterior, no entanto, neste caso o objetivo de fazer chars específicos maiores que outros é esconder algo como um botão para não ser pressionado pelo bot ou uma imagem que não será carregada. Assim, poderíamos medir a ação (ou a falta da ação) e saber se um char específico está presente dentro do texto.
Referência: Isso é mencionado como uma solução malsucedida neste relatório
Neste caso, poderíamos tentar vazar se um char está no texto carregando uma fonte falsa da mesma origem:
Se houver uma correspondência, a fonte será carregada de /static/bootstrap.min.css?q=1
. Embora não carregue com sucesso, o navegador deve armazená-la em cache, e mesmo que não haja cache, existe um mecanismo de 304 not modified, então a resposta deve ser mais rápida do que outras coisas.
No entanto, se a diferença de tempo da resposta em cache em relação à não em cache não for grande o suficiente, isso não será útil. Por exemplo, o autor mencionou: No entanto, após testar, descobri que o primeiro problema é que a velocidade não é muito diferente, e o segundo problema é que o bot usa a flag disk-cache-size=1
, o que é realmente atencioso.
Referência: Isso é mencionado como uma solução malsucedida neste relatório
Neste caso, você pode indicar CSS para carregar centenas de fontes falsas da mesma origem quando uma correspondência ocorre. Dessa forma, você pode medir o tempo que leva e descobrir se um caractere aparece ou não com algo como:
E o código do bot se parece com isto:
Então, se a fonte não corresponder, o tempo de resposta ao visitar o bot deve ser de aproximadamente 30 segundos. No entanto, se houver uma correspondência de fonte, várias solicitações serão enviadas para recuperar a fonte, causando atividade contínua na rede. Como resultado, levará mais tempo para satisfazer a condição de parada e receber a resposta. Portanto, o tempo de resposta pode ser usado como um indicador para determinar se há uma correspondência de fonte.
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)