DVWA靶场——CSRF (跨站脚本伪造)

📅 2026/7/5 1:44:07
DVWA靶场——CSRF (跨站脚本伪造)
CSRF跨站请求伪造全称为Cross-site request forgery简单来说是攻击者利用受害者尚未失效的身份认证信息诱骗受害者点击恶意链接或含有攻击代码的页面在受害者不知情的情况下以受害者的身份像服务器发起请求从而实现非法攻击改密。low:我们跟着指引输入我们需要更改的密码再确定密码可以看到直接更改成功了并且最重要的发现是我们改的密码的明文竟然直接显示在URL中用更改的密码试试能不能登录第一关成功了我原本的密码就是你用来登录DVWA的密码password就用不了了。说明这关确实没有任何验证就轻易更改了密码经过上面的尝试发现可以成功修改密码而且我们发现了URL那里的变化接下来我们从URL处入手再改一下首先先重置一下数据库把密码改回来。我们改成同样的元素按回车也能够更改成功。源码分析?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 prePassword Changed./pre; } else { // Issue with passwords matching echo prePasswords did not match./pre; } ((is_null($___mysqli_res mysqli_close($GLOBALS[___mysqli_ston]))) ? false : $___mysqli_res); } ?我们可以看到这里通过GET方式获取两次密码两次密码输入一致的话就可以直接带入数据中修改密码。Medium我们首先抓个包拦截正常请求 → 把密码参数改成自己的 → 保持Referer不变 → 放行。借用了合法的Referer骗过服务器这里可以看到虽然URL中显示的是123456但我们发送放行的数据包是password。这里还有第二种绕过方式需结合其他漏洞。通过文件上传漏洞植入恶意HTML → 访问该页面 → 自动提交CSRF请求。Referer自动变成127.0.0.1/xxx包含服务器域名检查通过。这里就不做演示了源码分析?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 prePassword Changed./pre; } else { // Issue with passwords matching echo prePasswords did not match./pre; } } else { // Didnt come from a trusted source echo preThat request didnt look correct./pre; } ((is_null($___mysqli_res mysqli_close($GLOBALS[___mysqli_ston]))) ? false : $___mysqli_res); } ?Medium级别的代码检查了保留变量 HTTP_REFERERhttp包头的Referer参数的值表示来源地址中是否包含SERVER_NAMEhttp包头的Host参数及要访问的主机名这里是127.0.0.3希望通过这种机制抵御CSRF攻击。High这个数据包中多了个我们熟悉的字样——token此处是令牌的意思并非ai领域的词元用token机制来防御CSRF。用户每次访问改密页面时服务器都会返回一个随机的token当浏览器向服务器发起请求时需要提交token参数而服务器在收到请求时会优先检查token只有token正确才会处理客户端的请求。这里因为对请求的token进行了验证所以比上两个等级的更加的安全。所以主要就在于如何获取到这个一次有效期的token第一个方法就是改包不动token的值直接放行和medium差不多第二就是利用XSS 注入代码让受害者的浏览器自己帮攻击者获取 Token 并发起请求第三就是跟暴力破解中用 Burp 的Macro宏功能自动提取 Token源码分析?php if( isset( $_GET[ Change ] ) ) { // Check Anti-CSRF token //可以看到加入了token机制 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 prePassword Changed./pre; } else { // Issue with passwords matching echo prePasswords did not match./pre; } ((is_null($___mysqli_res mysqli_close($GLOBALS[___mysqli_ston]))) ? false : $___mysqli_res); } // Generate Anti-CSRF token generateSessionToken(); ?Impossible?php if( isset( $_GET[ Change ] ) ) { // Check Anti-CSRF token checkToken( $_REQUEST[ user_token ], $_SESSION[ session_token ], index.php ); // Get input //输入原来的密码 $pass_curr $_GET[ password_current ]; $pass_new $_GET[ password_new ]; $pass_conf $_GET[ password_conf ]; // Sanitise current password input $pass_curr stripslashes( $pass_curr ); $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 ); // Check that the current password is correct $data $db-prepare( SELECT password FROM users WHERE user (:user) AND password (:password) LIMIT 1; ); $data-bindParam( :user, dvwaCurrentUser(), PDO::PARAM_STR ); $data-bindParam( :password, $pass_curr, PDO::PARAM_STR ); $data-execute(); // Do both new passwords match and does the current password match the user? if( ( $pass_new $pass_conf ) ( $data-rowCount() 1 ) ) { // It does! $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 ); // Update database with new password $data $db-prepare( UPDATE users SET password (:password) WHERE user (:user); ); $data-bindParam( :password, $pass_new, PDO::PARAM_STR ); $data-bindParam( :user, dvwaCurrentUser(), PDO::PARAM_STR ); $data-execute(); // Feedback for the user echo prePassword Changed./pre; } else { // Issue with passwords matching echo prePasswords did not match or current password incorrect./pre; } } // Generate Anti-CSRF token generateSessionToken(); ?要求我们先输入密码再修改攻击者不知道原始密码的情况下是无法发起 CSRF 攻击的。