文章目录
前记
- 今天是学习小迪安全的第五十六天,本节课的内容是关于CSRF的原理、防御方式以及如何去尝试绕过
- 内容不多,理解为主,让我们开始学习吧!
- 资料地址:
WEB攻防——第五十六天
CSRF请求伪造&Referer同源&置空&配合XSS&Token值校验&复用删除
什么是CSRF
- CSRF(
Cross-Site Request Forgery
),也叫跨站请求伪造,是一种网络攻击手段,攻击者通过诱导用户在已认证的状态下访问恶意链接或页面,迫使用户的浏览器向目标服务器发送非预期的请求,从而执行攻击者预设的操作(如转账、修改密码、发表评论等)。 - 其实很好理解,就像上面那张图一样,假设我现在抓到了支付宝的转账数据包如下:
http://www.alipay.com/pay.php?name=ling&account=12732834&money=10000
- 然后我们伪造一个网站,让这个网站去加载这个数据包,然后把这个网站发给别人
- 当受害者支付宝正好是登录状态(身份验证已经通过了),并且访问了我们的恶意网站,那么就会跳转到这个转账页面,如果没有做一些防护,那就会向我们转10000块
- 这个就是典型的CSRF攻击
利用条件
- 从上面可以看到,CSRF的利用条件呢有三点:
- 需要请求伪造的数据包
- 网站没有过滤防护或者有防护但可以绕过
- 受害者需要访问恶意网站才能触发
- 这里面最主要的就是第二条,基本能不能够形成危害就看网站的防护情况
CSRF - 无检测防护-检测&生成&利用
利用
- 无检测防护就是说开发者默认信任用户的所有操作,因此没有加一些
Token
、二次验证、来源检测等等 - 那这时候我们就可以通过BP去生成
CSRF
的POC
,将文件放到自己的网站下面,诱使受害者去点击访问 - 当然更多是配合
XSS
去打组合拳
实战案例
-
这里我们以CMS为例,然后首先是搭建,这里就按以前的方式搭建即可
-
然后创建完了之后我们进入后台:
-
然后左边这里有个账户管理,我们点击新增管理员用户,把所有的都选上(选不选都无所谓):
-
然后我们开启BP,点击下面的”保存“按钮抓包:
-
抓到包之后,我们右击选中
Engagement tools
->Generate CSRF PoC
:
-
进入如下页面:
-
点击右上角的
Options
,勾选第一个和最后的选项,如图所示:
-
最后点击
Regenerate
,就可以生成一个用于CSRF攻击的恶意网站了,然后我们点击Copy HTML
,将他保存为一个html
页面,放到自己的服务器上,这里就用虚拟机代替了,开启简单的服务器,恶意网址为http://192.168.0.129:8881/index.html
:
-
然后网站里面不要添加用户,将刚刚的数据包丢弃掉,保持网站只有这
admin
一个用户:
-
现在我们通过这个网站去访问刚刚的恶意网址,模拟我们发送恶意链接给受害者访问,注意到一个新的页面去输入网址:
-
等待一两秒中之后他就会返回成功的字样:
-
我们此时到后台页面一看,成功创建了一个新的管理员用户:
-
那这就是一个简单的CSRF攻击,那你可能会问,我怎么得到这个数据包呢?其实这里的话如果你能拿到这个网站的源码你就可以尝试去分析,如果没有源码的话,其实很难测,只能测一些常规用户的功能存不存在这个漏洞
CSRF - Referer&Origin同源-规则&上传&XSS
原理
Referer
和Origin
都是HTTP
请求头的一个字段,用于记录当前请求的来源页面 URL(即 “从哪个页面跳转到当前请求”)。- Referer & Origin同源策略是指:服务器通过检查请求头中的
Referer
/Origin
字段,验证请求是否来自可信的同源域名,以此判断请求是否合法。 Referer
和Origin
的区别:Origin
仅包含”协议 + 域名 + 端口“,相比于Referer来说更加简洁Referer
包含完整的URL来源,包括协议、域名、端口、路径、参数等
GET /index.html HTTP/1.1
Host: 192.168.0.129:8881
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0
Origin: http://192.168.0.129:8881
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.0.129:8881/index.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: close
实战案例
-
这里我们这就只研究
Referer
的验证,因为Origin
也是差不多的,然后我们使用的是zblog
-
我们先尝试之前的一个逻辑,因为这里也有添加用户(注意用户级别尽量小一点)的功能,那我们就尝试添加用户,然后抓包:
-
和上面一样,生成一个CSRF的伪造网站
add.html
,放到恶意网站上 -
现在我们在一个新窗口访问恶意网址,并且可以抓包看一看这个数据包:
-
可以看到它的
Referer
是http://192.168.0.129:8881/
,然后提示我们非法访问,说明这里就进行了拦截,那他是怎么一个拦截逻辑呢?我们可以看看源代码进行分析 -
首先我们捕获到的数据包中提交的地址是
/zb_system/cmd.php
,传入的参数为act=MemberPst
,那我们就直接找到这个文件,搜索一下这个参数就得了:
-
这里就找到了,我们看到这里有一个
CheckIsReferValid()
函数,很明显就是检查Referer
的东西,然后我们追踪看一下:
-
这里他先检查
CSRFToken
,先不管,先看下面的这个CheckHTTPRefererValid()
函数,继续追踪:
-
可以看到它会检查
HTTP_REFERER
这个属性,这个东西其实就是$_SERVER
中的一个属性,如果它为空,那就返回True
;如果它不是当前博客的网址,就返回false
,这里最骚的是使用的stripos()
函数去比较,也就是说只要里面包含博客的地址,都返回true
-
那这里我们可以怎么去绕过呢?根据代码可知,就两个绕过方式嘛:
Referer
头为空Referer
头中包含博客地址
-
那我们就首先尝试
Referer
头为空吧,设置的话是蛮简单的,就是在生成的代码中添加这段代码:
<head>
<!-- 添加Referrer Policy,禁止发送Referer头 -->
<meta name="referrer" content="no-referrer">
</head>
-
然后我们再次尝试CSRF攻击,并且抓个包看看它是否还有
Referer
头:
-
很明显地看到没有了
Referer
头,并且我们添加用户成功了,这里如果提示没有权限,记得每次操作都清除一下缓存 -
同样,我们演示一下第二种绕过方式,这里将
add.html
还原,把用户删掉,然后再次访问恶意链接抓包:
-
这里刚刚我们分析过了,那可以尝试直接加上
http://zblog.test:999/
:
Referer: http://192.168.0.129:8881/http://zblog.test:9999/
-
这里以免复现不出来,可以每个包都把上面的
Referer
包含进去,然后发包看看是否操作成功:
-
成功添加!
绕过方式
- 所以经过我们上面的演示,如果它开启了
Referer
头的验证,那我们可以从三方面去考虑:- Referer改成网站的域名:但是这个必须要改数据包才行,你总不能让用户帮你改吧,这个不现实;当然还有一种思路就是看能不能把这个文件名改成
http://[域名]:[端口]
的格式,这样加载的时候Referer
就会带上这个文件名,那就包含了这个可信域名,当然这是不现实的,因为不支持 - Referer头置空:可以尝试将
Referer
头置空,即带有这个Referer
头,但是没有数值,不过这也需要用户改包,不现实 - 删除Referer头:可以尝试将
Referer
头删除,这个是最好实现的,但能不能绕过就看它的代码逻辑
- Referer改成网站的域名:但是这个必须要改数据包才行,你总不能让用户帮你改吧,这个不现实;当然还有一种思路就是看能不能把这个文件名改成
- 其实这三方面本质就是看它的代码逻辑是怎么样的,一般对
Referer
头的检测就三种逻辑:- 全部对比:一一对应,严谨对比 => 配合xss或者上传(触发数据包保证是同一来源)
- 匹配对比:只要包含某个域名即可 => 直接访问
- 逻辑判断隐患:置空或删除
CSRF - Token校验-值删除&复用&留空
原理
Token
校验是一种通过随机生成的字符串(Token
) 验证请求合法性的安全机制。Token
作为客户端与服务器之间的 “秘密凭证”,用于证明请求是 “经授权的合法来源” 发起的,而非攻击者伪造。- 其实就是服务器每次都生成一个一次性的凭证给用户,用户每次操作之前都需要拿着这个凭证给服务器证明自己的身份,使用之后该
Token
就失效了,下一次操作又需要新的Token
实战案例
-
这里我们是用自己写的简单网站来做测试:
-
我们正常提交数据包他会回显我们提交的数据,这里我们提交之后抓包:
-
可以看到这里有个参数叫
csrf_token
,这个一般就是专门用来防止CSRF
的东西,现在我们将他复制出来,并且按照之前的逻辑生成一个CSRF
的恶意网站,然后放包 -
现在模拟受害者访问生成的恶意网站:
-
可以看到,这里它提示
CSRF Token
校验失败,说明我们拿着刚刚的Token
已经失效了
绕过方式
- 那你说如果遇到了这种
Token
就没办法了吗?也不一定,如果开发者的代码逻辑有问题,也可能导致绕过 - 最常见的就是三种情况:
- 复用:就是如果代码没有规定这个
Token
的失效时间,那它就可以重复使用 - 置空:可以尝试将
Token
的值置空去尝试能不能绕过验证 - 删除:也可以尝试将
Token
删除看看能不能绕过
- 复用:就是如果代码没有规定这个
- 基本遇到像
Cookie
、Token
这类验证也就这些方法,Cookie
你还可以猜一下,但Token
一般是猜不出来的