DOM Based XSS’i Anlamak

Selamlar,

Bu yazım önceki yazılarıma nazaran biraz farklı olacak. Geçmiş yazılarımın hemen hemen hepsi işin hep “pratik” yani teknik kısmına dahilken bu yazı işin “teorik” tarafına dahil olacak. Aslında hep işin teorisinin pratiğe göre daha önemli olduğunu düşünmüşümdür ancak nedense bloguma bunu hiç yansıtamadım. Hep teknik blog tutmuşum, hep teknik…

Konuşma fırsatı bulduğum eğitimlerde, seminerlerde, arkadaş ortamlarında, meetuplarda, sağda, solda kısacası heryerde işin ezberci kısmına karşı olduğumu hep söylemişimdir. X zafiyetinin nasıl exploit edileceğini değil, exploit ederken backgroundda gerçekleşen olaylar silsilesini anlayabilmekte yatıyor bence bütün iş. Bu yazıda da DOM Based XSS‘i “ya işte anchor’lu linklerin sonuna payloadı yazında olan tür değil mi bu DOM Based”  diye bilen kişilere hitaben yazıyorum. Hadi başlayalım…

DOM Nedir?

Document Object Model, “DOM”, “Belge Nesnesi Modeli” anlamlarına da gelmektedir. İnternet tarayıcıları girilen internet sayfasını bir belge, bu belge (sayfa) içerisinde bulunan tüm elemanları da nesne olarak kabul eder. Buna göre resim, yazı, form gibi tüm elemanlar nesnedir. İşte DOM sayfa içindeki herhangi bir nesnenin özelliğine müdahele edebilmemize, nesne özelliklerini değiştirebilmemize olanak sağlar. Bunu yapabilmek için de JavaScript gibi bazı script dilleri kullanmamız gerekir.[1]

Yani; bir HTML dökümanında JavaScript ile erişip herhangi bir işlem yapabildiğimiz tüm nesneler birer DOM’dur. Aşağıda Developer Tool tarafından DOMlar’ın nasıl higlight edildiğini görebilirsiniz.

1

omercitak.com‘a bir requestte bulunduğunuzda server size response olarak bir takım header ve istekte bulunduğumuz sayfanın HTML kodunu döndürecektir. Kullandığınız browser bu HTML kodunu yorumlayıp; DOMları üretecektir ve yukarıdaki resimdeki gibi bir hal alacaktır.

Not: Browserın HTML kodunu yorumlamasından kastım aslında bir browserın nasıl çalıştığını bilmektir. Konumuz bu olmadığı için oralara girmeyeceğim ama dostum Hana Can‘ın yazmış olduğu “Tarayıcılar Nasıl Çalışıyor” yazısını okuyarak bu konu hakkında bilgi sahibi olabilirsiniz.

Örneğin yukarıdaki resimdeki “id” atribütünün değeri “contents” olan “div” nesnesini aşağıdaki gibi bir seçici (selectors) ile seçebiliriz.

Not: Aşağıdaki kodları JQuery kütüphanesinin dahil edildiğini varsayarak yazıyorum.

var dom = $("div#contents");

Seçtiğimiz DOM üzerinden bir takım olaylar gerçekleştirelim. Örneğin nesnenin görünürlüğünü yani “display” özelliğini “none” yapalım.

var dom = $("div#contents");
dom.hide();

DOM Based XSS’i anlamak için öncelikle DOM u anlamak gerekiyor. Umarım buraya kadar DOM’u anlatabilmişimdir. Şimdi sonraki bölümlere geçelim

DOM Based XSS Nedir?

DOM Based XSS, aslında isminin birebir Türkçeleştirilmişidir. Yani “DOM Tabanlı XSS”, DOM yüzünden ortaya çıkan, sebebi DOM olan XSS demektir. Ama ne yazıkki aralarında iyi firmalarda çalışanlarında olduğu büyük bir güvenlik araştırmacısı grubu DOM Based XSS’i “adres çubuğunda sharp (#) işaretinden sonra payload yazılarak yapılan XSS” olarak biliyor. O yüzden bu yazıda üzerinden gideceğimiz testcase anchor üzerine olmayacak. Sanırım DOM Based XSS’i anchor üzerinden anlatmayan tek yazı da bu olacak.

Gel gelelim testcaseimize. Testcase ile mantığın biraz daha oturacağını düşünüyorum. Senaryomuz şu şekil; 2 adet dosyamız olacak.

users.php; database’deki kullanıcıların listelendiği ve yeni bir kullanıcı eklemek için gerekli input’un olduğu sayfa
process.php; database’e yeni bir kullanıcı eklemek için XHR yollayacağımız sayfa

process.php sayfası birnevi API gibi çalışacak. İşlemin sonucunu json olarak döndürecek ve content-type’ı application/json olacak.

process.php

<?php
header("Content-Type: application/json; charset=UTF-8");

$con = mysql_connect("localhost", "root", "root") or die("not connected");
$con = mysql_select_db("dom_xss", $con) or die("not selected");

call_user_func($_POST["action"], $_POST);

function create($params)
{
    mysql_query("insert into users (name) value ('" . $params["name"] . "')");
    echo '{"success":true,"message":"","total":0,"data":[],"object":{"id":5,"name":"' . $params["name"] . '"}}';
}

function users()
{
    $results = mysql_query("select * from users");

    $result = '[';
    while ($row = mysql_fetch_assoc($results)) {
        $result .= '{"text":"' . $row["name"] . '","data":{"id":' . $row["id"] . ',"name":"' . $row["name"] . '"}},';
    }
    $result = substr($result, 0, strlen($result) - 1);
    $result .= ']';

    echo $result;
}

users.php

<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script>
    $(document).ready(function () {
        getUsers();

        $("#create").click(function () {
            var name = $("#name").val();
            $.ajax({
                type: "POST",
                url: "connectors/index.php",
                data: "action=create&name=" + name,
                success: function (cevap) {
                    var name = cevap.object.name;
                    $("#info").html(name + " is created!");
                    getUsers();
                }
            });
        });
    });

    function getUsers() {
        $.ajax({
            type: "POST",
            url: "process.php",
            data: "action=users",
            success: function (result) {
                var a = '<ul>';
                for (var i = 0; i < result.length; i++) {
                    a += "<li>" + result[i].text + "</li>";
                }
                a += '<ul>';
                $("#result").html(a);
            }
        });
    }
</script>

<div id="info" style="background: greenyellow"></div>

<div id="result"></div>

<div id="create_box">
    <input type="text" id="name">
    <button id="create">create</button>
</div>

Kodları okuduktan sonra tekrar senaryonun üzerinden geçelim;

  1. users.php açılır açılmaz process.php’ye bir XHR yollanıyor ve database’deki kullanıcılar çekiliyor.
  2. Çekilen kullanıcılar JavaScript yardımı ile bir liste olarak ekrana basılıyor.
  3. Eğer yeni bir kullanıcı oluşturulmuş ise input’a girilen kayıt database’e eklenip, tekrar ilk 2 adım uygulanıyor (javascript’teki getUsers fonksiyonu ile)

Şimdi burada “process.php’de stored xss var” diyip sazanlama atlamamak lazım. Process.php’nin content-type‘ı application/json olduğundan çoğu browser o sayfada html kodu yorumlamayacaktır. Doğrudan ekrana basacaktır. Bakalım bu sayfada Firefox nasıl davranmış?

2 3

Yukarıdaki ilk resimde doğrudan sayfayı, 2. resimde ise sayfanın kaynağını görüyoruz. Her ikiside birebir aynı ve HTML kodu yorumlanmamış. Yorumlanmadığı içinde bir XSS saldırısında mağruz kalınmamış.

Gel gelelim users.php sayfasına. Users.php sayfası; process.php’den aldığı json çıktısını yorumlayarak DOM’lar oluşturuyordu. DOM oluştururken process.php’den aldığı verileride kullandığından ve process.php, users.php’ye browserın yorumlayacağı bir HTML kodu gönderdiğinden users.php de XSS zafiyetine rastlarız.

4 5

Yukarıdaki resimlerde de gördüğünüz gibi users.php’nin kaynak kodunda herhangi bir değişiklik olmamasına rağmen process.php’ye yapılan XHR ile ortaya XSS zafiyeti çıkmıştır.

Sonuç

Her ne kadar “Stored” gibi gözüksede aslında bu “DOM-Based Stored XSS” tir. Çünkü XSS’e sebep olan şey JavaScript tarafından oluşturulan DOM’dur. Buradaki isim karmaşıklığının sebebi ise sektörel bazlı yanlış isimlendirmedir.

Hep duymuşsunuzdur; XSS 3’e ayrılır derler. Reflected, DOM Based ve Stored. İşte buradaki karmaşıklığa sebep olan şey aslında bu yanlış 3’e ayırma.

Reflected ve Stored XSS’in tipidir. Mantıksal olarak zaten 2 tipten oluşabilir. Ya anlık olur, gelen requestte göre değişecek şekilde. Ya da bir yerde (database, file vs) saklanır. Anlık olana “Reflected” denir saklanana ise “Stored”.

DOM Based bir tip değildir. Adı üzerinde “DOM Tabanlı” yani “DOM Yüzünden”. Herkesin bildiği, yazının başında bahsettiğim anchor testcase’i bir “DOM Based Reflected” örneğidir. Yukarıda kodunu yazdığım testcase ise bir “DOM Based Stored” örneğidir.

Umarım aklınızı bulandırabilmişimdir ve DOM Based derken aslında ne kastedildiğini anlatabilmişimdir.

Kaynaklar

  1. https://tr.wikipedia.org/wiki/Document_Object_Model

Comments on this post

  1. Güzel bir yazı olmuş, eline sağlık

  2. ali

    güzel yazmışsın reis

  3. RootXyele

    peki bunun kolayca anlayamazmıyız hocam js ile çağırılıp çağırılmamasına mı bakmalıyız yalnızca

    • Neyi sormak istedigini anlamadim.

      • RootXyele

        yani demeye çalıştığım reflected olarak gelen parametreyi dom xss olarak tanımlayan şey yalnızca javascript blogu içerisinde çalışıp çalışmadığı mıdır?

  4. Hasan

    yaptığınız bu uygulamayı bizimde deneyebilmemiz için örnek veritabanınıda paylaşabilir misiniz?Tüm kodları githubda paylaşsanız çok iyi olur gerçekten.

  5. Sinan

    teşekkürler çok güzel bir anlatım olmuş

  6. mertbingol0

    eline sağlık abi çok teşekkür ederim. Kafa bulandırmadan net bir şekilde anlatmışsın. <3

  7. Furkan

    Çok Teşekkürler

  8. Ömer

    Kusura bakma hocam yazı güzel ama ben inan anlamadım bu nasıl bir güvenlik açığı oluştururki?

    Tamam burada sayfa içerisinde javascript kodu çalıştırarak;
    – Sayfada birşey basabiliriz
    – document.cookie ile cookie’leri görebiliriz.
    – load ile başka sayfaya yönlendirebilir
    – form post – get yapıp form falan gönderebilirim.

    Fakat şunu anlamadım örneğin ben a.com ‘da bu işi yapıyorum. Bunları zaten F12 console ilede yapabiliyorum.

    Adam cookie’de, local storage’da tuttuğu bilgiler zaten benim bilgilerim.

    Bunun ne açığı yapabileceğini anlayamadım.

    Sorma nedenim: innerHtml kullanıyorum kolay çünkü içerik yönetimde millet tutturmuş xss açığı cors açığı vs. Kardeşim tamam açık hackle diyorum yok birşey kendi verisini basıp duruyor tamam bas ne olacak?

    Yani bir örnek verirmisin ne olabilir ki?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.