CSRF漏洞很容易就可以被发现并利用。一眼看去很多站点好像在这方面都做得不错:当你检查针对敏感操作的请求时,他们往往会实施CSRF保护。有时候可能是一个在请求主体中的CSRF token,也有可能是一个referer字段检测,或者有时是一个特殊的HTTP头字段或者cookie字段。
但是CSRF的防御不代表它就不可以被绕过。今天我们讨论一些我如何绕过CSRF防御措施的技术。
所有的CSRF
不管哪种CSRF防御措施部署,你都可以先尝试如下两件事:点击劫持和更改请求方法。
点击劫持
在同一个功能端点利用点击劫持会绕过所有CSRF防御。因为从技术上讲,请求确实来自合法站点,如果易受攻击的端点所在页面容易遭受点击劫持攻击,那么所有的CSRF保护将变得没有效果,攻击者可以任意执行CSRF攻击。
更改请求方法
另外值得一试的方法就是更改请求的方法。如果要伪造的敏感请求是通过POST方法发送的,那么尝试将其转换为GET请求。如果操作时通过GET方法发送的,那么尝试转换为POST方法。应用程序可能仍然执行操作,且通常没有任何保护机制。
例如,如下请求:
POST /change_password
POST body:
new_password=qwerty
可以被改写成
GET /change_password?new_password=qwerty
CSRF token的防御措施
因为一个站点使用了CSRF token不代表这个token是有效验证对应请求操作的,可以尝试如下方法绕过CSRF的token保护。
删除token参数或发送空token
不发送token也可以正常请求数据是因为这种逻辑错误在应用程序中非常常见:应用程序有时会在token存在的时候或者token参数不为空的时候检查token的有效性。这种情况下,如果一个请求不包含token或者token值为空,那么也是有可能绕过CSRF的防御的。
例如,合法请求如下
POST /change_password
POST body:
new_password=qwerty &csrf_tok=871caef0757a4ac9691aceb9aad8b65b
那么实施这种请求:
POST /change_password
POST body:
new_password=qwerty
或这种:
POST /change_password
POST body:
new_password=qwerty&csrf_tok=
使用另一个session的CSRF token
应用程序可能只是检查token是否合法,但是不检查token是否确实归属于当前用户。如果是这种情况的话,你可以在payload中硬编码一个合法有效的token即可。
如果一个受害者的token是871caef0757a4ac9691aceb9aad8b65b,你自己的token是YOUR_TOKEN,那么你可以很容易获取到自己的token但很难获取到受害者的token。尝试在payload中提供自己的token来绕过CSRF防御。
换句话说,原本应该发送如下请求:
POST /change_password
POST body:
new_password=qwerty &csrf_tok=871caef0757a4ac9691aceb9aad8b65b
但是改成发送这个请求:
POST /change_password
POST body:
new_password=qwerty &csrf_tok=YOUR_TOKEN
Session固定
有时候站点使用一个双提交cookie作为一个CSRF的防御措施。这个表明这个请求需要包含一个cookie,其值为随机token值,且同时在请求参数中也有一个字段值为该随机token值。如果值相同,那么请求是合法的。这种防御形式是非常常见的。
如果一个双提交cookie用在了防御措施中,那么这个应用有可能没有将有效的token保存在服务器端。所以它没有办法指定token是否合法,并且也有可能很少检查cookie中的token值和参数中token值是不是一样的。这代表你可以发送一个假token,然后仍然可以有效实施CSRF攻击。
这种攻击包含两个步骤:第一步,你使用一个session固定技术去确认受害者的浏览器使用的是你提供的包含假token的session,然后第二步在参数中使用同一个token来执行这个CSRF攻击。
session固定。这是一个可以让你控制受害者的cookie存储的攻击;
执行如下请求来实施CSRF攻击
POST /change_password
Cookie: CSRF_TOK=FAKE_TOKEN;
POST body:
new_password=qwerty &csrf_tok=FAKE_TOKEN
Referer字段的CSRF防御
如果attack.com是一个可控的域名,bank.com是一个要攻击的域名。这个站点没有使用CSRF token但是检查了referer字段。你应该怎么做?
移除referer字段
和发送一个空token值相同,有时候你只需简单地移除referer字段就可以绕过CSRF防御。你可以添加如下meta标签到存在漏洞的页面。
应用程序可能只是在发送后才会验证,这种情况下你可以绕过其CSRF防御。
绕过正则表达式
如果referer检查是基于白名单的,你可以尝试绕过验证URL的正则表达式。例如,你可以尝试在referer的URL中将受害者域名置于二级域名区域或者URL目录区域。
如果一个站点在referer字段检查“bank.com”字段,那么“bank.com.attacker.com"或”attakcer.com/bank.com"可能可以绕过这种检测。