作者:niubl@TSRC

1. 漏洞簡介

2017年9月28日,公司掃描器發現某業務存在一例任意文件讀取漏洞,團隊跟進分析后發現這是Node.js和Express共同導致的一個通用漏洞。在我們準備告知官方時,發現Node.js官網于9月29號給出了漏洞公告,對應的CVE編號為CVE-2017-14849。

1.1 關于Node.js

Node.js是一個Javascript運行環境(runtime),發布于2009年5月,由Ryan Dahl開發,實質是對Chrome V8引擎進行了封裝。Node.js對一些特殊用例進行優化,提供替代的API,使得V8在非瀏覽器環境下運行得更好。

1.2 關于Express

Express 是一個簡潔而靈活的 node.js Web應用框架, 提供一系列強大特性幫助你創建各種Web應用。Express 不對 node.js 已有的特性進行二次抽象,我們只是在它之上擴展了Web應用所需的功能。豐富的HTTP工具以及來自Connect框架的中間件隨取隨用,創建強健、友好的API變得快速又簡單。

1.3 漏洞影響

Node.js 8.5.0 + Express 3.19.0-3.21.2
Node.js 8.5.0 + Express 4.11.0-4.15.5

2. 漏洞演示

  1. 安裝Node.js 8.5.0
  2. 下載并解壓express-4.15.5.zip
  3. expresss-4.15.5目錄下執行npm install
  4. expresss-4.15.5/examples/static-files目錄里執行nodejs index.js
  5. 使用POC測試(web監聽了5678端口,默認3000)如下圖

3. 漏洞分析

Express依賴Send組件,Send組件0.11.0-0.15.6版本pipe()函數中,如圖:

Send模塊通過normalize('.' + sep + path)標準化路徑path后,并沒有賦值給path,而是僅僅判斷了下是否存在目錄跳轉字符。如果我們能繞過目錄跳轉字符的判斷,就能把目錄跳轉字符帶入545行的join(root, path)函數中,跳轉到我們想要跳轉到的目錄中,這是Send模塊的一個bug,目前已經修復。

再來看Node.js,Node.js 8.5.0對path.js文件中的normalizeStringPosix函數進行了修改,使其能夠對路徑做到如下的標準化:

assert.strictEqual(path.posix.normalize('bar/foo../..'), 'bar');

新的修改帶來了問題,通過單步調試我們發現,可以通過foo../../和目錄跳轉字符一起注入到路徑中,foo../../可以把變量isAboveRoot設置為false(代碼161行),并且在代碼135行把自己刪掉;變量isAboveRootfalse的情況下,可以在foo../../兩邊設置同樣數量的跳轉字符,讓他們同樣在代碼135行把自己刪除,這樣就可以構造出一個帶有跳轉字符,但是通過normalizeStringPosix函數標準化后又會全部自動移除的payload,這個payload配合上面提到的Send模塊bug就能夠成功的返回一個我們想要的物理路徑,最后在Send模塊中讀取并返回文件。normalizeStringPosix函數如下圖:

4. 參考鏈接


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/439/