前言
CSRF 介绍
CSRF(跨站请求伪造),全称为Cross-site request forgery,简单来说,是指利用受害者尚未失效的身份认证信息(Cookie、会话等),诱骗其点击恶意链接或者访问包含攻击代码的页面,在受害人不知情的情况下以受害者的身份向(身份认证信息所对应的)服务器发送请求,从而完成非法操作(如转账、改密等)。
CSRF 与 XSS 区别
XSS是通过修改页面Javascript等代码后,发给用户从而实现盗取Cookie信息,之后利用Cookie进行登陆网站等操作。非法操作是黑客。
CSRF并没有盗取Cookie信息,而是通过用户直接利用Cookie进行操作。非法操作并不是黑客,而是用户本身。
CSRF通常和XSS联合利用。
Low
源码分析
通过GET方式获取两次密码,两次密码输入一致的话,就可以直接带入数据中修改密码。
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' ] ) ) { $pass_new = $_GET [ 'password_new' ]; $pass_conf = $_GET [ 'password_conf' ]; if ( $pass_new == $pass_conf ) { $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 ); $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>' ); echo "<pre>Password Changed.</pre>" ; } else { echo "<pre>Passwords did not match.</pre>" ; } ((is_null ($___mysqli_res = mysqli_close ($GLOBALS ["___mysqli_ston" ]))) ? false : $___mysqli_res ); } ?>
漏洞复现
Test Credentials 使用 DVWA 默认密码(admin/password)进行登录
CSRF 输入两次密码123456进行修改密码
然后我们就能获取到CSRF漏洞利用链接
1 http://192.168.199.236/dvwa/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change#
使用 admin/123456 去 Test Credentials 进行测试发现账户密码已被更改
Medium
源码分析
HTTP_REFERER表示数据包中的referer字段数据包的来源链接
SERVER_NAME表示数据包中的host访问的主机地址
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' ] ) ) { if ( stripos ( $_SERVER [ 'HTTP_REFERER' ] ,$_SERVER [ 'SERVER_NAME' ]) !== false ) { $pass_new = $_GET [ 'password_new' ]; $pass_conf = $_GET [ 'password_conf' ]; if ( $pass_new == $pass_conf ) { $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 ); $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>' ); echo "<pre>Password Changed.</pre>" ; } else { echo "<pre>Passwords did not match.</pre>" ; } } else { echo "<pre>That request didn't look correct.</pre>" ; } ((is_null ($___mysqli_res = mysqli_close ($GLOBALS ["___mysqli_ston" ]))) ? false : $___mysqli_res ); } ?>
漏洞利用
使用BurpSuite抓包获取Referer
我们想直接尝试使用Low漏洞利用方法
1 http://192.168.199.236/dvwa/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change#
BurpSuite返回信息如下
相比之下缺少了Referer
因为 HTTP_REFERER 和 SERVER_NAME 的限制我们无法进行修改
那我们就在BurpSuite上补充回Referer
1 Referer: http://192.168.199.236/dvwa/vulnerabilities/csrf/
BurpSuite修改放行后成功修改
High
源码分析
High引入了Anti-CSRF Token机制进行身份验证
用户每次访问改密页面时,服务器会返回一个随机的token,向服务器发起请求时,需要提交token参数,而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端请求。
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 <?php $change = false ;$request_type = "html" ;$return_message = "Request Failed" ;if ($_SERVER ['REQUEST_METHOD' ] == "POST" && array_key_exists ("CONTENT_TYPE" , $_SERVER ) && $_SERVER ['CONTENT_TYPE' ] == "application/json" ) { $data = json_decode (file_get_contents ('php://input' ), true ); $request_type = "json" ; if (array_key_exists ("HTTP_USER_TOKEN" , $_SERVER ) && array_key_exists ("password_new" , $data ) && array_key_exists ("password_conf" , $data ) && array_key_exists ("Change" , $data )) { $token = $_SERVER ['HTTP_USER_TOKEN' ]; $pass_new = $data ["password_new" ]; $pass_conf = $data ["password_conf" ]; $change = true ; } } else { if (array_key_exists ("user_token" , $_REQUEST ) && array_key_exists ("password_new" , $_REQUEST ) && array_key_exists ("password_conf" , $_REQUEST ) && array_key_exists ("Change" , $_REQUEST )) { $token = $_REQUEST ["user_token" ]; $pass_new = $_REQUEST ["password_new" ]; $pass_conf = $_REQUEST ["password_conf" ]; $change = true ; } } if ($change ) { checkToken ( $token , $_SESSION [ 'session_token' ], 'index.php' ); if ( $pass_new == $pass_conf ) { $pass_new = mysqli_real_escape_string ($GLOBALS ["___mysqli_ston" ], $pass_new ); $pass_new = md5 ( $pass_new ); $current_user = dvwaCurrentUser (); $insert = "UPDATE `users` SET password = '" . $pass_new . "' WHERE user = '" . $current_user . "';" ; $result = mysqli_query ($GLOBALS ["___mysqli_ston" ], $insert ); $return_message = "Password Changed." ; } else { $return_message = "Passwords did not match." ; } mysqli_close ($GLOBALS ["___mysqli_ston" ]); if ($request_type == "json" ) { generateSessionToken (); header ("Content-Type: application/json" ); print json_encode (array ("Message" =>$return_message )); exit ; } else { echo "<pre>" . $return_message . "</pre>" ; } } generateSessionToken ();?>
漏洞利用
XSS (Stored) High
由于输入长度有限度,先使用BurpSuite进行抓包
修改txtName里面的内容
1 <iframe src ="../csrf/" onload =alert(frames[0].document.getElementsByName( 'user_token ')[0 ].value )>
逐一放包就会找到我们需要的Token值
CSRF High
输入需要修改的密码并使用BurpSuite抓包
将token值修改为我们从XSS(Stored)抓取到的token值
BurpSuite 翻新后密码就已经被修改了
参考 & 引用
https://zhuanlan.zhihu.com/p/565945383
https://www.cnblogs.com/chadlas/articles/15708801.html
https://blog.csdn.net/weixin_46709219/article/details/109325123