MongoDB ve NoSQL Injection Zafiyetleri

Merhaba

İlişkisel veri tabanı sistemlerine yapılan SQL Injection saldırılarının temeli query string oluşturulmasına dayanmaktadır. Bu durumda saldırı vektörü oluşturulmasında mantıklar, gelenekselleşmiş ilişkisel veri tabanı sistemleri mimarileri gölgesinde kalmaktadır.

Örnek olarak aşağıdaki gibi URL’in var olduğunu kabul edelim.

www.mehmetince.net/haber.php?id=137

Bu link üzerinde GET talebi ile taşınan id değişkeninin %99 ihtimalle SQL sorgusunun WHERE statement’ında kullanılacağı düşünülmektedir.

SELECT * FROM haberler WHERE id = '$id'

Bu durumda saldırı yapılan noktada kullanılan veri tabanı sorgusu yukarıdaki gibi düşünülecektir ve saldırı payloadları bu alınan kararlar neticesinde şekillenecektir. Eğer saldırı vektörleri bu geleneksel yaklaşım çerçevesinde kalırsa, noSQL veri tabanı sistemlerinde herhangi bir zafiyet tespiti yapılması imkansızdır.

mongoDB ve NoSQL Injection Test Ortamı

Benim gibi ilişkisel veri tabanı sistemlerinin kullanıldığı uygulamlara sızma testi gerçekleştiren insanların, atak vektörü oluşturma noktasında mongoDB ile problemler yaşayacağı aşikardır. Çünkü MySQL veya PostgreSQL gibi veri tabanı sistemlerini kullanan uygulamalarda genellikle query string’ler oluşturulmaktadır ve sql injection saldırıları bu query string’in oluşturulmasında ki kontrol hatalarından kaynaklanmaktadır. İş MongoDB’ye geldiğindeyse query string olayı alışılagelmiş bir mantıkta değildir.

Örnek olarak mongoDB veri tabanına aşağıdaki şekilde 3 adet kayıt girilmiştir.

mince@rootlab www $ mongo
MongoDB shell version: 2.4.9
connecting to: test
> use test
switched to db test
> show collections
products
system.indexes
zaa
> db.products.insert({'isim':'MEHMET'});
> db.products.insert({'isim':'AHMET'});
> db.products.insert({'isim':'ISMAIL'});

Şimdiyse bu kullanıcıları veri tabanında arayarak ekrana yazan PHP uygulamasının kaynak kodlarını okuyalım.

<?php
/**
 * Created by PhpStorm.
 * User: mince
 * Date: 3/26/14
 * Time: 4:11 PM
 */
$name = '';
if(@$_GET['name'])
    $name = $_GET['name'];
try {
    // a new MongoDB connection
    $conn = new Mongo('localhost');

    // connect to test database
    $db = $conn->test;

    // a new products collection object
    $collection = $db->products;

    // fetch all product documents
    $cursor = $collection->find(array(
        "isim" => $name
    ));

    // How many results found
    $num_docs = $cursor->count();

    if( $num_docs > 0 )
    {
        // loop over the results
        foreach ($cursor as $obj)
        {
            echo 'Name: ' . $obj['isim'] . "<br>";
        }
    }
    else
    {
        // if no products are found, we show this message
        echo "No products found \n";
    }
    // close the connection to MongoDB
    $conn->close();
}
catch ( MongoConnectionException $e )
{
    echo $e->getMessage();
}
catch ( MongoException $e )
{
    echo $e->getMessage();
}
?>
<html>
    <head>
        <title>MongoDB</title>
    </head>
    <body>
        <div style="text-align: center">
            <form>
                <input name="name" type="text" placeholder="Name" />
                <input name="submit" type="submit" value="Submit">
            </form>
        </div>
    </body>
</html>

Kullanıcı girdisi olarak alınan isim değişkeni veri tabanında aratılıp, sonuçlar ekrana yazılmaktadır. Bu uygulamayı sqlmap ile test ettiğimizde herhangi bir güvenlik açığı bulunamamış olacaktır. Çünkü güvenlik testi yaklaşımında veri tabani sistemi olarak ilişkisel veri tabanı kullanıldığı varsayılarak ciddi bir hata yapılmıştır.

MongoDB NoSQL Injection Saldırı Vektörü

Uygulamaya kullanıcı girisi olarka MEHMET yazıldığında aşağıdaki sonuç elde edilmiş olacaktır.

http://localhost/web-challange/mongodb/?name=MEHMET

# ÇIKTI
Name: MEHMET

Eğer saldırı vektörü olarak aşağıdaki şekilde bir talep gönderilirse bu sefer veri tabanında ki tüm veriler ekrana yazılmış olacaktır. Tıpkı ilişkisel veri tabanı sistemlerine yapılan saldırılarki tırnak or tırnak bir tırnak eşittir tırnak bir = ‘ or ‘1’=’1 saldırıları gibi.

http://localhost/web-challange/mongodb/?name[$ne]=merhababenaslindayokum

Dönen sayfa sonucu ise aşağıdadır.

Screenshot from 2014-03-26 16:36:46

 

Peki bu durum nasıl oluştu ?

Kullanıcı girdi olarak name[$ne]=merhababenaslindayokum yazıldığında oluşan mongoDB objesi aşağıdadır.

> db.products.find( {isim : { $ne:'merhababenaslindayokum' } } );
{ "_id" : ObjectId("5332df781e2e830daff39077"), "selam" : 123 }
{ "_id" : ObjectId("5332e2ec859dd9536165c065"), "isim" : "MEHMET" }
{ "_id" : ObjectId("5332e2fd859dd9536165c066"), "isim" : "AHMET" }
{ "_id" : ObjectId("5332e303859dd9536165c067"), "isim" : "ISMAIL" }
{ "_id" : ObjectId("5332e6af859dd9536165c068"), "isim" : "ISMAIL" }

Yani mongoDB değeri merhababenaslindayokum string’ine eşit olmayan dökümanları döndürecektir.

Sonuç

2014 yılı nodeJS, mongoDB , socket.io gibi gelenekselleşmiş web uygulaması mimarilerinden çok farklı mimarilerde projelere gebe durumdadır.

Web uygulama sızma testleri gerçekleştiren ekiplerin/bireylerin bu yeni teknolojilere ve mantıklarına aşina olmaları çok önemlidir. Aksi takdirde bu yazıda demo olarak gösterine güvenlik açığı, login modüllerinde Authentication Bypass olarak karşınıza çıkacaktır ve kritik düzey bu bulgunun tespiti pentester tarafından gerçekleştirilemeyecektir. Bu nedenledir ki en development olmadan, pentester olunamaz.